diff --git a/chain/src/main/java/org/ethereum/beacon/chain/DefaultBeaconChain.java b/chain/src/main/java/org/ethereum/beacon/chain/DefaultBeaconChain.java index 9c59c0f10..aa3fca282 100644 --- a/chain/src/main/java/org/ethereum/beacon/chain/DefaultBeaconChain.java +++ b/chain/src/main/java/org/ethereum/beacon/chain/DefaultBeaconChain.java @@ -89,7 +89,7 @@ private void initializeStorage() { Hash32 initialStateRoot = spec.hash_tree_root(initialState); BeaconBlock genesis = initialGenesis.withStateRoot(initialStateRoot); - Hash32 genesisRoot = spec.signed_root(genesis); + Hash32 genesisRoot = spec.signing_root(genesis); BeaconTuple tuple = BeaconTuple.of(genesis, initialState); tupleStorage.put(tuple); @@ -120,7 +120,7 @@ public synchronized boolean insert(BeaconBlock block) { blockVerifier.verify(block, preBlockState); if (!blockVerification.isPassed()) { logger.warn("Block verification failed: " + blockVerification + ": " + - block.toString(spec.getConstants(), parentState.getGenesisTime(), spec::signed_root)); + block.toString(spec.getConstants(), parentState.getGenesisTime(), spec::signing_root)); return false; } @@ -151,7 +151,7 @@ public synchronized boolean insert(BeaconBlock block) { .toString( spec.getConstants(), newTuple.getState().getGenesisTime(), - spec::signed_root), + spec::signing_root), String.format("%.3f", ((double) total) / 1_000_000_000d)); return true; @@ -165,13 +165,13 @@ public BeaconTuple getRecentlyProcessed() { private void updateFinality(BeaconState previous, BeaconState current) { if (previous.getFinalizedEpoch().less(current.getFinalizedEpoch())) { Hash32 finalizedRoot = - spec.get_block_root( + spec.get_block_root_at_slot( current, spec.get_epoch_start_slot(current.getFinalizedEpoch())); chainStorage.getFinalizedStorage().set(finalizedRoot); } if (previous.getCurrentJustifiedEpoch().less(current.getCurrentJustifiedEpoch())) { Hash32 justifiedRoot = - spec.get_block_root( + spec.get_block_root_at_slot( current, spec.get_epoch_start_slot(current.getCurrentJustifiedEpoch())); chainStorage.getJustifiedStorage().set(justifiedRoot); } @@ -186,7 +186,7 @@ private BeaconStateEx pullParentState(BeaconBlock block) { } private boolean exist(BeaconBlock block) { - Hash32 blockHash = spec.signed_root(block); + Hash32 blockHash = spec.signing_root(block); return chainStorage.getBlockStorage().get(blockHash).isPresent(); } diff --git a/chain/src/main/java/org/ethereum/beacon/chain/observer/ObservableBeaconState.java b/chain/src/main/java/org/ethereum/beacon/chain/observer/ObservableBeaconState.java index 64040b00c..0c3947ba3 100644 --- a/chain/src/main/java/org/ethereum/beacon/chain/observer/ObservableBeaconState.java +++ b/chain/src/main/java/org/ethereum/beacon/chain/observer/ObservableBeaconState.java @@ -56,7 +56,7 @@ public String toString(@Nullable BeaconChainSpec spec) { String committee = ""; if (spec != null) { committee = " Proposer/Committee: " - + spec.get_beacon_proposer_index(getLatestSlotState(), getLatestSlotState().getSlot()) + + spec.get_beacon_proposer_index(getLatestSlotState()) + " " + spec.get_crosslink_committees_at_slot( getLatestSlotState(), getLatestSlotState().getSlot()).get(0).getCommittee() @@ -64,7 +64,7 @@ public String toString(@Nullable BeaconChainSpec spec) { } return "ObservableBeaconState[head=" - + (spec != null ? spec.signed_root(head).toStringShort() : head.toString(null ,null, null)) + + (spec != null ? spec.signing_root(head).toStringShort() : head.toString(null ,null, null)) + ", latestState: " + committee + latestSlotState.toStringShort(spec == null ? null : spec.getConstants()) diff --git a/chain/src/main/java/org/ethereum/beacon/chain/observer/ObservableStateProcessorImpl.java b/chain/src/main/java/org/ethereum/beacon/chain/observer/ObservableStateProcessorImpl.java index f8a96fd6a..1271ba8c9 100644 --- a/chain/src/main/java/org/ethereum/beacon/chain/observer/ObservableStateProcessorImpl.java +++ b/chain/src/main/java/org/ethereum/beacon/chain/observer/ObservableStateProcessorImpl.java @@ -1,20 +1,29 @@ package org.ethereum.beacon.chain.observer; +import java.time.Duration; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.stream.Collectors; import org.ethereum.beacon.chain.BeaconChainHead; import org.ethereum.beacon.chain.BeaconTuple; import org.ethereum.beacon.chain.BeaconTupleDetails; import org.ethereum.beacon.chain.LMDGhostHeadFunction; import org.ethereum.beacon.chain.storage.BeaconChainStorage; import org.ethereum.beacon.chain.storage.BeaconTupleStorage; +import org.ethereum.beacon.consensus.BeaconChainSpec; import org.ethereum.beacon.consensus.BeaconStateEx; import org.ethereum.beacon.consensus.HeadFunction; -import org.ethereum.beacon.consensus.BeaconChainSpec; import org.ethereum.beacon.consensus.transition.EmptySlotTransition; import org.ethereum.beacon.core.BeaconBlock; import org.ethereum.beacon.core.BeaconState; import org.ethereum.beacon.core.operations.Attestation; import org.ethereum.beacon.core.state.PendingAttestation; import org.ethereum.beacon.core.types.BLSPubkey; +import org.ethereum.beacon.core.types.EpochNumber; import org.ethereum.beacon.core.types.SlotNumber; import org.ethereum.beacon.core.types.ValidatorIndex; import org.ethereum.beacon.schedulers.Scheduler; @@ -25,15 +34,7 @@ import org.javatuples.Pair; import org.reactivestreams.Publisher; import reactor.core.publisher.Flux; - -import java.time.Duration; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.stream.Collectors; +import tech.pegasys.artemis.util.uint.UInt64s; public class ObservableStateProcessorImpl implements ObservableStateProcessor { private static final int MAX_TUPLE_CACHE_SIZE = 256; @@ -53,7 +54,7 @@ public class ObservableStateProcessorImpl implements ObservableStateProcessor { private Cache tupleDetails = new LRUCache<>(MAX_TUPLE_CACHE_SIZE); private final List attestationBuffer = new ArrayList<>(); - private final Map, Attestation> attestationCache = new HashMap<>(); + private final Map, Attestation> attestationCache = new HashMap<>(); private final Schedulers schedulers; private final SimpleProcessor headStream; @@ -100,17 +101,16 @@ private void runTaskInSeparateThread(Runnable task) { } private void onNewSlot(SlotNumber newSlot) { - // From spec: Verify that attestation.data.slot <= state.slot - MIN_ATTESTATION_INCLUSION_DELAY - // < attestation.data.slot + SLOTS_PER_EPOCH - // state.slot - MIN_ATTESTATION_INCLUSION_DELAY < attestation.data.slot + SLOTS_PER_EPOCH - // state.slot - MIN_ATTESTATION_INCLUSION_DELAY - SLOTS_PER_EPOCH < attestation.data.slot - SlotNumber slotMinimum = - newSlot - .minus(spec.getConstants().getSlotsPerEpoch()) - .minus(spec.getConstants().getMinAttestationInclusionDelay()); + /* From spec: + attestation_slot = get_attestation_slot(state, attestation) + assert attestation_slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot <= attestation_slot + SLOTS_PER_EPOCH */ + SlotNumber slotMinimum = newSlot + .minusSat(spec.getConstants().getSlotsPerEpoch()) + .minusSat(spec.getConstants().getMinAttestationInclusionDelay()); + EpochNumber epochMinimum = spec.slot_to_epoch(slotMinimum); runTaskInSeparateThread( () -> { - purgeAttestations(slotMinimum); + purgeAttestations(epochMinimum); newSlot(newSlot); }); } @@ -119,11 +119,11 @@ private void doHardWork() { if (latestState == null) { return; } - List attestations = drainAttestations(latestState.getSlot()); + List attestations = drainAttestations(spec.get_current_epoch(latestState)); for (Attestation attestation : attestations) { List participants = - spec.get_attestation_participants( + spec.get_attesting_indices( latestState, attestation.getData(), attestation.getAggregationBitfield()); List pubKeys = spec.mapIndicesToPubKeys(latestState, participants); @@ -135,19 +135,19 @@ private void doHardWork() { } private synchronized void addValidatorAttestation(BLSPubkey pubKey, Attestation attestation) { - attestationCache.put(Pair.with(pubKey, attestation.getData().getSlot()), attestation); + attestationCache.put(Pair.with(pubKey, attestation.getData().getTargetEpoch()), attestation); } private synchronized void onNewAttestation(Attestation attestation) { attestationBuffer.add(attestation); } - private synchronized List drainAttestations(SlotNumber uptoSlotInclusive) { + private synchronized List drainAttestations(EpochNumber upToEpochInclusive) { List ret = new ArrayList<>(); Iterator it = attestationBuffer.iterator(); while (it.hasNext()) { Attestation att = it.next(); - if (att.getData().getSlot().lessEqual(uptoSlotInclusive)) { + if (att.getData().getTargetEpoch().lessEqual(upToEpochInclusive)) { ret.add(att); it.remove(); } @@ -171,27 +171,27 @@ private void addAttestationsFromState(BeaconState beaconState) { pendingAttestations.addAll(beaconState.getPreviousEpochAttestations().listCopy()); for (PendingAttestation pendingAttestation : pendingAttestations) { List participants = - spec.get_attestation_participants( + spec.get_attesting_indices( beaconState, pendingAttestation.getData(), pendingAttestation.getAggregationBitfield()); List pubKeys = spec.mapIndicesToPubKeys(beaconState, participants); - SlotNumber slot = pendingAttestation.getData().getSlot(); + EpochNumber targetEpoch = pendingAttestation.getData().getTargetEpoch(); pubKeys.forEach( pubKey -> { - removeValidatorAttestation(pubKey, slot); + removeValidatorAttestation(pubKey, targetEpoch); }); } } - private synchronized void removeValidatorAttestation(BLSPubkey pubkey, SlotNumber slot) { - attestationCache.remove(Pair.with(pubkey, slot)); + private synchronized void removeValidatorAttestation(BLSPubkey pubkey, EpochNumber epoch) { + attestationCache.remove(Pair.with(pubkey, epoch)); } - /** Purges all entries for slot and before */ - private synchronized void purgeAttestations(SlotNumber slot) { + /** Purges all entries for epoch and before */ + private synchronized void purgeAttestations(EpochNumber targetEpoch) { attestationCache.entrySet() - .removeIf(entry -> entry.getValue().getData().getSlot().lessEqual(slot)); + .removeIf(entry -> entry.getValue().getData().getTargetEpoch().less(targetEpoch)); } private synchronized Map> copyAttestationCache() { @@ -228,7 +228,7 @@ private void newSlot(SlotNumber newSlot) { private void updateCurrentObservableState(BeaconTupleDetails head, SlotNumber slot) { assert slot.greaterEqual(head.getBlock().getSlot()); - PendingOperations pendingOperations = new PendingOperationsState(copyAttestationCache()); + PendingOperations pendingOperations = new PendingOperationsState(spec, copyAttestationCache()); if (slot.greater(head.getBlock().getSlot())) { BeaconStateEx stateUponASlot = emptySlotTransition.apply(head.getFinalState(), slot); latestState = stateUponASlot; @@ -253,7 +253,7 @@ private void updateCurrentObservableState(BeaconTupleDetails head, SlotNumber sl } private void updateHead() { - PendingOperations pendingOperations = new PendingOperationsState(copyAttestationCache()); + PendingOperations pendingOperations = new PendingOperationsState(spec, copyAttestationCache()); BeaconBlock newHead = headFunction.getHead( validatorRecord -> pendingOperations.getLatestAttestation(validatorRecord.getPubKey())); @@ -266,7 +266,7 @@ private void updateHead() { (head) -> { BeaconTuple newHeadTuple = tupleStorage - .get(spec.signed_root(head)) + .get(spec.signing_root(head)) .orElseThrow( () -> new IllegalStateException("Beacon tuple not found for new head ")); return new BeaconTupleDetails(newHeadTuple); diff --git a/chain/src/main/java/org/ethereum/beacon/chain/observer/PendingOperations.java b/chain/src/main/java/org/ethereum/beacon/chain/observer/PendingOperations.java index fddd061e8..e112b6e44 100644 --- a/chain/src/main/java/org/ethereum/beacon/chain/observer/PendingOperations.java +++ b/chain/src/main/java/org/ethereum/beacon/chain/observer/PendingOperations.java @@ -2,6 +2,7 @@ import java.util.List; import java.util.Optional; +import org.ethereum.beacon.core.BeaconState; import org.ethereum.beacon.core.operations.Attestation; import org.ethereum.beacon.core.operations.ProposerSlashing; import org.ethereum.beacon.core.operations.Transfer; @@ -23,7 +24,7 @@ public interface PendingOperations { List peekAttesterSlashings(int maxCount); List peekAggregatedAttestations( - int maxCount, SlotNumber minSlotExclusive, SlotNumber maxSlotInclusive); + int maxCount, BeaconState state, SlotNumber minSlotExclusive, SlotNumber maxSlotInclusive); List peekExits(int maxCount); diff --git a/chain/src/main/java/org/ethereum/beacon/chain/observer/PendingOperationsState.java b/chain/src/main/java/org/ethereum/beacon/chain/observer/PendingOperationsState.java index ec5b4a76f..aa8a8532f 100644 --- a/chain/src/main/java/org/ethereum/beacon/chain/observer/PendingOperationsState.java +++ b/chain/src/main/java/org/ethereum/beacon/chain/observer/PendingOperationsState.java @@ -9,10 +9,12 @@ import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; +import org.ethereum.beacon.consensus.BeaconChainSpec; +import org.ethereum.beacon.core.BeaconState; import org.ethereum.beacon.core.operations.Attestation; +import org.ethereum.beacon.core.operations.ProposerSlashing; import org.ethereum.beacon.core.operations.Transfer; import org.ethereum.beacon.core.operations.VoluntaryExit; -import org.ethereum.beacon.core.operations.ProposerSlashing; import org.ethereum.beacon.core.operations.attestation.AttestationData; import org.ethereum.beacon.core.operations.slashing.AttesterSlashing; import org.ethereum.beacon.core.types.BLSPubkey; @@ -24,15 +26,20 @@ public class PendingOperationsState implements PendingOperations { Map> attestations; + private final BeaconChainSpec spec; - public PendingOperationsState(Map> attestations) { + public PendingOperationsState( + BeaconChainSpec spec, Map> attestations) { + this.spec = spec; this.attestations = attestations; } @Override public Optional getLatestAttestation(BLSPubkey pubKey) { return Optional.ofNullable(attestations.get(pubKey)) - .map(atts -> Collections.max(atts, Comparator.comparing(att -> att.getData().getSlot()))); + .map( + atts -> + Collections.max(atts, Comparator.comparing(att -> att.getData().getTargetEpoch()))); } @Override @@ -52,18 +59,22 @@ public List peekAttesterSlashings(int maxCount) { @Override public List peekAggregatedAttestations( - int maxCount, SlotNumber minSlotExclusive, SlotNumber maxSlotInclusive) { + int maxCount, BeaconState state, SlotNumber minSlotExclusive, SlotNumber maxSlotInclusive) { Map> attestationsBySlot = - getAttestations() - .stream() - .filter(attestation -> attestation.getData().getSlot().greater(minSlotExclusive)) - .filter(attestation -> attestation.getData().getSlot().lessEqual(maxSlotInclusive)) + getAttestations().stream() + .filter(attestation -> { + SlotNumber attestationSlot = + spec.get_attestation_slot(state, attestation.getData()); + // minExclusive < attestationSlot <= maxSlotInclusive + return minSlotExclusive.less(attestationSlot) + && attestationSlot.lessEqual(maxSlotInclusive); + }) .collect(groupingBy(Attestation::getData)); return attestationsBySlot .entrySet() .stream() - .sorted(Comparator.comparing(e -> e.getKey().getSlot())) + .sorted(Comparator.comparing(e -> e.getKey().getTargetEpoch())) .limit(maxCount) .map(entry -> aggregateAttestations(entry.getValue())) .collect(Collectors.toList()); @@ -83,7 +94,7 @@ private Attestation aggregateAttestations(List attestations) { BLS381.Signature aggregatedSignature = BLS381.Signature.aggregate( attestations.stream() - .map(Attestation::getAggregateSignature) + .map(Attestation::getSignature) .map(BLS381.Signature::create) .collect(Collectors.toList())); BLSSignature aggSign = BLSSignature.wrap(aggregatedSignature.getEncoded()); diff --git a/chain/src/test/java/org/ethereum/beacon/chain/DefaultBeaconChainTest.java b/chain/src/test/java/org/ethereum/beacon/chain/DefaultBeaconChainTest.java index 84dce2936..ab16df449 100644 --- a/chain/src/test/java/org/ethereum/beacon/chain/DefaultBeaconChainTest.java +++ b/chain/src/test/java/org/ethereum/beacon/chain/DefaultBeaconChainTest.java @@ -3,7 +3,6 @@ import java.util.Collections; import java.util.stream.IntStream; import org.ethereum.beacon.chain.storage.BeaconChainStorage; -import org.ethereum.beacon.chain.storage.BeaconChainStorageFactory; import org.ethereum.beacon.chain.storage.impl.SSZBeaconChainStorageFactory; import org.ethereum.beacon.chain.storage.impl.SerializerFactory; import org.ethereum.beacon.consensus.BeaconChainSpec; @@ -22,8 +21,8 @@ import org.ethereum.beacon.core.BeaconBlock; import org.ethereum.beacon.core.BeaconBlockBody; import org.ethereum.beacon.core.BeaconState; -import org.ethereum.beacon.core.spec.SpecConstants; import org.ethereum.beacon.core.state.Eth1Data; +import org.ethereum.beacon.core.types.BLSSignature; import org.ethereum.beacon.core.types.Time; import org.ethereum.beacon.db.Database; import org.ethereum.beacon.pow.DepositContract.ChainStart; @@ -69,10 +68,10 @@ private BeaconBlock createBlock( BeaconBlock block = new BeaconBlock( spec.get_current_slot(parent.getState(), currentTime), - spec.signed_root(parent.getBlock()), + spec.signing_root(parent.getBlock()), Hash32.ZERO, BeaconBlockBody.EMPTY, - spec.getConstants().getEmptySignature()); + BLSSignature.ZERO); BeaconState state = perSlotTransition.apply(new BeaconStateExImpl(parent.getState())); return block.withStateRoot(spec.hash_tree_root(state)); diff --git a/chain/src/test/java/org/ethereum/beacon/chain/storage/BeaconBlockStorageTest.java b/chain/src/test/java/org/ethereum/beacon/chain/storage/BeaconBlockStorageTest.java index eca0a607b..2ad9dcbf1 100644 --- a/chain/src/test/java/org/ethereum/beacon/chain/storage/BeaconBlockStorageTest.java +++ b/chain/src/test/java/org/ethereum/beacon/chain/storage/BeaconBlockStorageTest.java @@ -20,7 +20,7 @@ public class BeaconBlockStorageTest { private BeaconBlockStorage create(BeaconChainSpec spec) { return BeaconBlockStorageImpl.create( Database.inMemoryDB(), - ObjectHasher.createSSZOverKeccak256(spec.getConstants()), + ObjectHasher.createSSZOverSHA256(spec.getConstants()), SerializerFactory.createSSZ(spec.getConstants())); } diff --git a/chain/src/test/java/org/ethereum/beacon/chain/util/ObservableBeaconStateTestUtil.java b/chain/src/test/java/org/ethereum/beacon/chain/util/ObservableBeaconStateTestUtil.java index 11d1a7cc3..2b020bece 100644 --- a/chain/src/test/java/org/ethereum/beacon/chain/util/ObservableBeaconStateTestUtil.java +++ b/chain/src/test/java/org/ethereum/beacon/chain/util/ObservableBeaconStateTestUtil.java @@ -18,6 +18,7 @@ import org.ethereum.beacon.pow.DepositContract.ChainStart; import org.mockito.Mockito; import tech.pegasys.artemis.ethereum.core.Hash32; +import tech.pegasys.artemis.util.uint.UInt64; public class ObservableBeaconStateTestUtil { @@ -47,7 +48,7 @@ public static ObservableBeaconState createInitialState( ChainStart chainStart = new ChainStart( Time.ZERO, - new Eth1Data(Hash32.random(random), Hash32.random(random)), + new Eth1Data(Hash32.random(random), UInt64.ZERO, Hash32.random(random)), Collections.emptyList()); InitialStateTransition stateTransition = new InitialStateTransition(chainStart, spec); diff --git a/chain/src/test/java/org/ethereum/beacon/chain/util/PendingOperationsTestUtil.java b/chain/src/test/java/org/ethereum/beacon/chain/util/PendingOperationsTestUtil.java index 8cf564e24..309af7c50 100644 --- a/chain/src/test/java/org/ethereum/beacon/chain/util/PendingOperationsTestUtil.java +++ b/chain/src/test/java/org/ethereum/beacon/chain/util/PendingOperationsTestUtil.java @@ -34,7 +34,7 @@ public static PendingOperations mockPendingOperations( when(pendingOperations.getAttestations()).thenReturn(attestations); when(pendingOperations.peekProposerSlashings(anyInt())).thenReturn(proposerSlashings); when(pendingOperations.peekAttesterSlashings(anyInt())).thenReturn(attesterSlashings); - when(pendingOperations.peekAggregatedAttestations(anyInt(), any(), any())) + when(pendingOperations.peekAggregatedAttestations(anyInt(), any(), any(), any())) .thenReturn(aggregateAttestations); when(pendingOperations.peekExits(anyInt())).thenReturn(voluntaryExits); return pendingOperations; diff --git a/chain/src/test/java/org/ethereum/beacon/chain/util/SampleObservableState.java b/chain/src/test/java/org/ethereum/beacon/chain/util/SampleObservableState.java index 2d27812c9..d94b27bed 100644 --- a/chain/src/test/java/org/ethereum/beacon/chain/util/SampleObservableState.java +++ b/chain/src/test/java/org/ethereum/beacon/chain/util/SampleObservableState.java @@ -81,7 +81,7 @@ public SlotNumber getGenesisSlot() { deposits = anyDeposits.getValue0(); depositKeys = anyDeposits.getValue1(); - eth1Data = new Eth1Data(Hash32.random(rnd), Hash32.random(rnd)); + eth1Data = new Eth1Data(Hash32.random(rnd), UInt64.ZERO, Hash32.random(rnd)); chainStart = new ChainStart(Time.of(genesisTime.getSeconds()), eth1Data, deposits); InitialStateTransition initialTransition = new InitialStateTransition(chainStart, spec); @@ -94,9 +94,7 @@ public SlotNumber getGenesisSlot() { spec.getObjectHasher(), SerializerFactory.createSSZ(specConstants)) .create(db); - // TODO BeaconBlockVerifier blockVerifier = (block, state) -> VerificationResult.PASSED; - // TODO BeaconStateVerifier stateVerifier = (block, state) -> VerificationResult.PASSED; beaconChain = new DefaultBeaconChain( diff --git a/consensus/src/main/java/org/ethereum/beacon/consensus/BeaconChainSpec.java b/consensus/src/main/java/org/ethereum/beacon/consensus/BeaconChainSpec.java index c68bf56f8..415751f12 100644 --- a/consensus/src/main/java/org/ethereum/beacon/consensus/BeaconChainSpec.java +++ b/consensus/src/main/java/org/ethereum/beacon/consensus/BeaconChainSpec.java @@ -42,7 +42,7 @@ public interface BeaconChainSpec /** * Creates a BeaconChainSpec instance with given {@link SpecConstants}, {@link - * Hashes#keccak256(BytesValue)} as a hash function and {@link SSZObjectHasher} as an object + * Hashes#sha256(BytesValue)} as a hash function and {@link SSZObjectHasher} as an object * hasher. * * @param constants a chain getConstants(). Schedulers::currentTime is passed @@ -126,11 +126,11 @@ public Builder withBlsVerifyProofOfPossession(boolean blsVerifyProofOfPossession } public Builder withDefaultHashFunction() { - return withHashFunction(Hashes::keccak256); + return withHashFunction(Hashes::sha256); } public Builder withDefaultHasher(SpecConstants constants) { - return withHasher(ObjectHasher.createSSZOverKeccak256(constants)); + return withHasher(ObjectHasher.createSSZOverSHA256(constants)); } public Builder enableCache() { diff --git a/consensus/src/main/java/org/ethereum/beacon/consensus/hasher/ObjectHasher.java b/consensus/src/main/java/org/ethereum/beacon/consensus/hasher/ObjectHasher.java index 0ed425468..10a4471f6 100644 --- a/consensus/src/main/java/org/ethereum/beacon/consensus/hasher/ObjectHasher.java +++ b/consensus/src/main/java/org/ethereum/beacon/consensus/hasher/ObjectHasher.java @@ -13,8 +13,8 @@ */ public interface ObjectHasher { - static ObjectHasher createSSZOverKeccak256(SpecConstants specConstants) { - return SSZObjectHasher.createIncremental(specConstants, Hashes::keccak256); + static ObjectHasher createSSZOverSHA256(SpecConstants specConstants) { + return SSZObjectHasher.createIncremental(specConstants, Hashes::sha256); } /** diff --git a/consensus/src/main/java/org/ethereum/beacon/consensus/spec/BlockProcessing.java b/consensus/src/main/java/org/ethereum/beacon/consensus/spec/BlockProcessing.java index 5fd3120b4..cd900f5fa 100644 --- a/consensus/src/main/java/org/ethereum/beacon/consensus/spec/BlockProcessing.java +++ b/consensus/src/main/java/org/ethereum/beacon/consensus/spec/BlockProcessing.java @@ -1,89 +1,97 @@ package org.ethereum.beacon.consensus.spec; -import static java.util.stream.Collectors.toList; -import static org.ethereum.beacon.core.spec.SignatureDomains.ATTESTATION; -import static org.ethereum.beacon.core.spec.SignatureDomains.BEACON_BLOCK; +import static org.ethereum.beacon.core.spec.SignatureDomains.BEACON_PROPOSER; import static org.ethereum.beacon.core.spec.SignatureDomains.RANDAO; -import java.util.Arrays; +import java.util.ArrayList; import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; +import java.util.stream.Stream; import org.ethereum.beacon.core.BeaconBlock; +import org.ethereum.beacon.core.BeaconBlockHeader; import org.ethereum.beacon.core.BeaconState; import org.ethereum.beacon.core.MutableBeaconState; import org.ethereum.beacon.core.operations.Attestation; +import org.ethereum.beacon.core.operations.Deposit; import org.ethereum.beacon.core.operations.ProposerSlashing; import org.ethereum.beacon.core.operations.Transfer; import org.ethereum.beacon.core.operations.VoluntaryExit; import org.ethereum.beacon.core.operations.attestation.AttestationData; -import org.ethereum.beacon.core.operations.attestation.AttestationDataAndCustodyBit; -import org.ethereum.beacon.core.operations.attestation.Crosslink; import org.ethereum.beacon.core.operations.slashing.AttesterSlashing; -import org.ethereum.beacon.core.state.Eth1DataVote; +import org.ethereum.beacon.core.operations.slashing.IndexedAttestation; +import org.ethereum.beacon.core.spec.SignatureDomains; import org.ethereum.beacon.core.state.PendingAttestation; -import org.ethereum.beacon.core.state.ShardCommittee; import org.ethereum.beacon.core.state.ValidatorRecord; import org.ethereum.beacon.core.types.BLSPubkey; -import org.ethereum.beacon.core.types.ShardNumber; +import org.ethereum.beacon.core.types.BLSSignature; +import org.ethereum.beacon.core.types.Gwei; +import org.ethereum.beacon.core.types.SlotNumber; import org.ethereum.beacon.core.types.ValidatorIndex; -import org.ethereum.beacon.crypto.BLS381.PublicKey; import tech.pegasys.artemis.ethereum.core.Hash32; import tech.pegasys.artemis.util.bytes.Bytes32s; -import tech.pegasys.artemis.util.collections.ReadList; import tech.pegasys.artemis.util.uint.UInt64; +import tech.pegasys.artemis.util.uint.UInt64s; /** * Block processing part. * * @see Per-block + * href="https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#per-block-processing">Per-block * processing in the spec. */ public interface BlockProcessing extends HelperFunction { default void verify_block_header(BeaconState state, BeaconBlock block) { - Hash32 headerRoot = signed_root(block); - - // Verify that bls_verify( - // pubkey=state.validator_registry[get_beacon_proposer_index(state, state.slot)].pubkey, - // message=proposal_root, - // signature=block.signature, - // domain=get_domain(state.fork, get_current_epoch(state), DOMAIN_PROPOSAL)). - ValidatorIndex proposerIndex = get_beacon_proposer_index(state, state.getSlot()); - BLSPubkey publicKey = state.getValidatorRegistry().get(proposerIndex).getPubKey(); - UInt64 domain = get_domain(state.getFork(), get_current_epoch(state), BEACON_BLOCK); - - assertTrue(bls_verify(publicKey, headerRoot, block.getSignature(), domain)); + /* Verify that the slots match + assert block.slot == state.slot */ + assertTrue(block.getSlot().equals(state.getSlot())); + /* Verify that the parent matches + assert block.previous_block_root == signing_root(state.latest_block_header) */ + assertTrue(block.getPreviousBlockRoot().equals(signing_root(state.getLatestBlockHeader()))); + + /* Verify proposer is not slashed + proposer = state.validator_registry[get_beacon_proposer_index(state)] + assert not proposer.slashed */ + ValidatorRecord proposer = state.getValidatorRegistry().get(get_beacon_proposer_index(state)); + assertTrue(!proposer.getSlashed()); + + /* Verify proposer signature + assert bls_verify(proposer.pubkey, signing_root(block), block.signature, get_domain(state, DOMAIN_BEACON_PROPOSER)) */ + assertTrue(bls_verify( + proposer.getPubKey(), + signing_root(block), + block.getSignature(), + get_domain(state, BEACON_PROPOSER) + )); } default void process_block_header(MutableBeaconState state, BeaconBlock block) { - // Verify that the slots match - assertTrue(block.getSlot().equals(state.getSlot())); - // Verify that the parent matches - assertTrue(block.getPreviousBlockRoot().equals(signed_root(state.getLatestBlockHeader()))); - // Save current block as the new latest block - state.setLatestBlockHeader(get_temporary_block_header(block)); + /* Save current block as the new latest block + state.latest_block_header = BeaconBlockHeader( + slot=block.slot, + previous_block_root=block.previous_block_root, + block_body_root=hash_tree_root(block.body), + ) */ + state.setLatestBlockHeader(new BeaconBlockHeader( + block.getSlot(), + block.getPreviousBlockRoot(), + Hash32.ZERO, + hash_tree_root(block.getBody()), + BLSSignature.ZERO)); } default void verify_randao(BeaconState state, BeaconBlock block) { - // Let proposer = state.validator_registry[get_beacon_proposer_index(state, state.slot)]. - ValidatorRecord proposer = - state - .getValidatorRegistry() - .get(get_beacon_proposer_index(state, state.getSlot())); - - /* assert bls_verify( - pubkey=proposer.pubkey, - message_hash=hash_tree_root(get_current_epoch(state)), - signature=block.body.randao_reveal, - domain=get_domain(state.fork, get_current_epoch(state), DOMAIN_RANDAO) - ) */ - assertTrue(bls_verify( - proposer.getPubKey(), - hash_tree_root(get_current_epoch(state)), - block.getBody().getRandaoReveal(), - get_domain(state.getFork(), get_current_epoch(state), RANDAO))); + /* proposer = state.validator_registry[get_beacon_proposer_index(state)] + Verify that the provided randao value is valid + assert bls_verify(proposer.pubkey, hash_tree_root(get_current_epoch(state)), block.body.randao_reveal, get_domain(state, DOMAIN_RANDAO)) */ + ValidatorRecord proposer = state.getValidatorRegistry().get(get_beacon_proposer_index(state)); + assertTrue( + bls_verify( + proposer.getPubKey(), + hash_tree_root(get_current_epoch(state)), + block.getBody().getRandaoReveal(), + get_domain(state, RANDAO) + ) + ); } default void process_randao(MutableBeaconState state, BeaconBlock block) { @@ -94,203 +102,372 @@ default void process_randao(MutableBeaconState state, BeaconBlock block) { hash(block.getBody().getRandaoReveal())))); } + /* + def process_eth1_data(state: BeaconState, block: BeaconBlock) -> None: + state.eth1_data_votes.append(block.body.eth1_data) + if state.eth1_data_votes.count(block.body.eth1_data) * 2 > SLOTS_PER_ETH1_VOTING_PERIOD: + state.latest_eth1_data = block.body.eth1_data + */ default void process_eth1_data(MutableBeaconState state, BeaconBlock block) { - /* for eth1_data_vote in state.eth1_data_votes: - # If someone else has already voted for the same hash, add to its counter - if eth1_data_vote.eth1_data == block.body.eth1_data: - eth1_data_vote.vote_count += 1 - return */ - for (int i = 0; i < state.getEth1DataVotes().size(); i++) { - Eth1DataVote eth1_data_vote = state.getEth1DataVotes().get(i); - // If someone else has already voted for the same hash, add to its counter - if (eth1_data_vote.getEth1Data().equals(block.getBody().getEth1Data())) { - state.getEth1DataVotes().update(i, vote -> - new Eth1DataVote(vote.getEth1Data(), vote.getVoteCount().increment())); - return; - } + state.getEth1DataVotes().add(block.getBody().getEth1Data()); + long votes_count = state.getEth1DataVotes().stream() + .filter(v -> v.equals(block.getBody().getEth1Data())) + .count(); + if (votes_count * 2 > getConstants().getSlotsPerEth1VotingPeriod().getValue()) { + state.setLatestEth1Data(block.getBody().getEth1Data()); } + } + + default void verify_proposer_slashing(BeaconState state, ProposerSlashing proposer_slashing) { + ValidatorRecord proposer = state.getValidatorRegistry().get(proposer_slashing.getProposerIndex()); + + /* Verify that the epoch is the same + assert slot_to_epoch(proposer_slashing.header_1.slot) == slot_to_epoch(proposer_slashing.header_2.slot) */ + assertTrue(slot_to_epoch(proposer_slashing.getHeader1().getSlot()) + .equals(slot_to_epoch(proposer_slashing.getHeader2().getSlot()))); + + /* But the headers are different + assert proposer_slashing.header_1 != proposer_slashing.header_2 */ + assertTrue(!proposer_slashing.getHeader1().equals(proposer_slashing.getHeader2())); + + /* Check proposer is slashable + assert is_slashable_validator(proposer, get_current_epoch(state)) */ + assertTrue(is_slashable_validator(proposer, get_current_epoch(state))); - // If we're seeing this hash for the first time, make a new counter - state.getEth1DataVotes().add( - new Eth1DataVote(block.getBody().getEth1Data(), UInt64.valueOf(1))); + /* Signatures are valid + for header in (proposer_slashing.header_1, proposer_slashing.header_2): + domain = get_domain(state, DOMAIN_BEACON_PROPOSER, slot_to_epoch(header.slot)) + assert bls_verify(proposer.pubkey, signing_root(header), header.signature, domain) */ + Stream.of(proposer_slashing.getHeader1(), proposer_slashing.getHeader2()).forEach(header -> { + UInt64 domain = get_domain(state, BEACON_PROPOSER, slot_to_epoch(header.getSlot())); + assertTrue(bls_verify( + proposer.getPubKey(), + signing_root(header), + header.getSignature(), + domain + )); + }); } /* """ Process ``ProposerSlashing`` transaction. - Note that this function mutates ``state``. """ */ default void process_proposer_slashing(MutableBeaconState state, ProposerSlashing proposer_slashing) { slash_validator(state, proposer_slashing.getProposerIndex()); } + default void verify_attester_slashing(BeaconState state, AttesterSlashing attester_slashing) { + IndexedAttestation attestation1 = attester_slashing.getAttestation1(); + IndexedAttestation attestation2 = attester_slashing.getAttestation2(); + + /* assert is_slashable_attestation_data(attestation_1.data, attestation_2.data) + assert verify_indexed_attestation(state, attestation_1) + assert verify_indexed_attestation(state, attestation_2) */ + assertTrue(is_slashable_attestation_data(attestation1.getData(), attestation2.getData())); + assertTrue(verify_indexed_attestation(state, attestation1)); + assertTrue(verify_indexed_attestation(state, attestation2)); + } + /* """ Process ``AttesterSlashing`` transaction. - Note that this function mutates ``state``. """ */ default void process_attester_slashing(MutableBeaconState state, AttesterSlashing attester_slashing) { - List slashable_indices = - attester_slashing.getSlashableAttestation1().getValidatorIndices().intersection( - attester_slashing.getSlashableAttestation2().getValidatorIndices()).stream() - .filter(index -> !state.getValidatorRegistry().get(index).getSlashed()) - .collect(toList()); - - for (ValidatorIndex index : slashable_indices) { - slash_validator(state, index); + IndexedAttestation attestation1 = attester_slashing.getAttestation1(); + IndexedAttestation attestation2 = attester_slashing.getAttestation2(); + + + /* slashed_any = False + attesting_indices_1 = attestation1.custody_bit_0_indices + attestation1.custody_bit_1_indices + attesting_indices_2 = attestation2.custody_bit_0_indices + attestation2.custody_bit_1_indices */ + boolean slashed_any = false; + List attesting_indices_1 = new ArrayList<>(); + attesting_indices_1.addAll(attestation1.getCustodyBit0Indices().listCopy()); + attesting_indices_1.addAll(attestation1.getCustodyBit1Indices().listCopy()); + List attesting_indices_2 = new ArrayList<>(); + attesting_indices_2.addAll(attestation2.getCustodyBit0Indices().listCopy()); + attesting_indices_2.addAll(attestation2.getCustodyBit1Indices().listCopy()); + + /* for index in set(attesting_indices_1).intersection(attesting_indices_2): + if is_slashable_validator(state.validator_registry[index], get_current_epoch(state)): + slash_validator(state, index) + slashed_any = True + assert slashed_any */ + List intersection = new ArrayList<>(attesting_indices_1); + intersection.retainAll(attesting_indices_2); + for (ValidatorIndex index : intersection) { + if (is_slashable_validator(state.getValidatorRegistry().get(index), get_current_epoch(state))) { + slash_validator(state, index); + slashed_any = true; + } } + assertTrue(slashed_any); } default void verify_attestation(BeaconState state, Attestation attestation) { AttestationData data = attestation.getData(); - // Verify that attestation.data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot - // < attestation.data.slot + SLOTS_PER_EPOCH - assertTrue(state.getSlot() - .greaterEqual(data.getSlot().plus(getConstants().getMinAttestationInclusionDelay()))); - assertTrue(state.getSlot().less(data.getSlot().plus(getConstants().getSlotsPerEpoch()))); - - // # Can't submit attestations too quickly - // assert attestation.data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot - assertTrue(data.getSlot() - .plus(getConstants().getMinAttestationInclusionDelay()).lessEqual(state.getSlot())); - - /* # Verify that the justified epoch and root is correct - if slot_to_epoch(attestation.data.slot) >= get_current_epoch(state): - # Case 1: current epoch attestations - assert attestation.data.source_epoch == state.current_justified_epoch - assert attestation.data.source_root == state.current_justified_root - else: - # Case 2: previous epoch attestations - assert attestation.data.source_epoch == state.previous_justified_epoch - assert attestation.data.source_root == state.previous_justified_root */ + /* attestation_slot = get_attestation_slot(state, attestation) + assert attestation_slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot <= attestation_slot + SLOTS_PER_EPOCH */ + SlotNumber attestation_slot = get_attestation_slot(state, data); + assertTrue( + attestation_slot.plus(getConstants().getMinAttestationInclusionDelay()).lessEqual(state.getSlot()) + && state.getSlot().lessEqual(attestation_slot.plus(getConstants().getSlotsPerEpoch())) + ); - if (slot_to_epoch(data.getSlot()).greaterEqual(get_current_epoch(state))) { - assertTrue(data.getSourceEpoch().equals(state.getCurrentJustifiedEpoch())); - assertTrue(data.getSourceRoot().equals(state.getCurrentJustifiedRoot())); - } else { - assertTrue(data.getSourceEpoch().equals(state.getPreviousJustifiedEpoch())); - assertTrue(data.getSourceRoot().equals(state.getPreviousJustifiedRoot())); - } + /* Check target epoch, source epoch, source root, and source crosslink + data = attestation.data + assert (data.target_epoch, data.source_epoch, data.source_root, data.previous_crosslink_root) in { + (get_current_epoch(state), state.current_justified_epoch, state.current_justified_root, hash_tree_root(state.current_crosslinks[data.shard])), + (get_previous_epoch(state), state.previous_justified_epoch, state.previous_justified_root, hash_tree_root(state.previous_crosslinks[data.shard])), + } */ + boolean current_epoch_attestation = + data.getTargetEpoch().equals(get_current_epoch(state)) + && data.getSourceEpoch().equals(state.getCurrentJustifiedEpoch()) + && data.getSourceRoot().equals(state.getCurrentJustifiedRoot()) + && data.getPreviousCrosslinkRoot().equals(hash_tree_root(state.getCurrentCrosslinks().get(data.getShard()))); + boolean previous_epoch_attestation = + data.getTargetEpoch().equals(get_previous_epoch(state)) + && data.getSourceEpoch().equals(state.getPreviousJustifiedEpoch()) + && data.getSourceRoot().equals(state.getPreviousJustifiedRoot()) + && data.getPreviousCrosslinkRoot().equals(hash_tree_root(state.getPreviousCrosslinks().get(data.getShard()))); + assertTrue(current_epoch_attestation || previous_epoch_attestation); - // Check crosslink data - /* assert attestation.data.crosslink_data_root == ZERO_HASH # [to be removed in phase 1] - crosslinks = state.current_crosslinks if slot_to_epoch(attestation.data.slot) == get_current_epoch(state) else state.previous_crosslinks - assert crosslinks[attestation.data.shard] == attestation.data.previous_crosslink */ - assertTrue(Hash32.ZERO.equals(data.getCrosslinkDataRoot())); - ReadList crosslinks = - slot_to_epoch(data.getSlot()).equals(get_current_epoch(state)) ? - state.getCurrentCrosslinks() : state.getPreviousCrosslinks(); - assertTrue(crosslinks.get(data.getShard()).equals(data.getPreviousCrosslink())); - - // assert attestation.custody_bitfield == b'\x00' * len(attestation.custody_bitfield) # [TO BE REMOVED IN PHASE 1] - assertTrue(attestation.getCustodyBitfield().isZero()); - // assert attestation.aggregation_bitfield != b'\x00' * len(attestation.aggregation_bitfield) - assertTrue(!attestation.getAggregationBitfield().isZero()); - - // crosslink_committee = [ - // committee for committee, shard in get_crosslink_committees_at_slot(state, attestation.data.slot) - // if shard == attestation.data.shard - // ][0] - Optional crosslink_committee_opt = - get_crosslink_committees_at_slot(state, data.getSlot()).stream() - .filter(c -> c.getShard().equals(data.getShard())) - .findFirst(); - assertTrue(crosslink_committee_opt.isPresent()); - List crosslink_committee = crosslink_committee_opt.get().getCommittee(); - - // for i in range(len(crosslink_committee)): - // if get_bitfield_bit(attestation.aggregation_bitfield, i) == 0b0: - // assert get_bitfield_bit(attestation.custody_bitfield, i) == 0b0 - for (int i = 0; i < crosslink_committee.size(); i++) { - if (attestation.getAggregationBitfield().getBit(i) == false) { - assertTrue(attestation.getCustodyBitfield().getBit(i) == false); - } - } + /* Check crosslink data root + assert data.crosslink_data_root == ZERO_HASH # [to be removed in phase 1] */ + assertTrue(data.getCrosslinkDataRoot().equals(Hash32.ZERO)); - // participants = get_attestation_participants(state, attestation.data, attestation.aggregation_bitfield) - List participants = - get_attestation_participants(state, data, attestation.getAggregationBitfield()); - - // custody_bit_1_participants = get_attestation_participants(state, attestation.data, attestation.custody_bitfield) - List custody_bit_1_participants = - get_attestation_participants(state, data, attestation.getCustodyBitfield()); - // custody_bit_0_participants = [i in participants for i not in custody_bit_1_participants] - List custody_bit_0_participants = participants.stream() - .filter(i -> !custody_bit_1_participants.contains(i)).collect(Collectors.toList()); - - // assert bls_verify_multiple( - // pubkeys=[ - // bls_aggregate_pubkeys([state.validator_registry[i].pubkey for i in custody_bit_0_participants]), - // bls_aggregate_pubkeys([state.validator_registry[i].pubkey for i in custody_bit_1_participants]), - // ], - // messages=[ - // hash_tree_root(AttestationDataAndCustodyBit(data=attestation.data, custody_bit=0b0)), - // hash_tree_root(AttestationDataAndCustodyBit(data=attestation.data, custody_bit=0b1)), - // ], - // signature=attestation.aggregate_signature, - // domain=get_domain(state.fork, slot_to_epoch(attestation.data.slot), DOMAIN_ATTESTATION), - // ) - List pubKeys1 = mapIndicesToPubKeys(state, custody_bit_0_participants); - PublicKey groupPublicKey1 = bls_aggregate_pubkeys(pubKeys1); - List pubKeys2 = mapIndicesToPubKeys(state, custody_bit_1_participants); - PublicKey groupPublicKey2 = bls_aggregate_pubkeys(pubKeys2); - assertTrue(bls_verify_multiple( - Arrays.asList(groupPublicKey1, groupPublicKey2), - Arrays.asList( - hash_tree_root(new AttestationDataAndCustodyBit(data, false)), - hash_tree_root(new AttestationDataAndCustodyBit(data, true))), - attestation.getAggregateSignature(), - get_domain(state.getFork(), slot_to_epoch(data.getSlot()), ATTESTATION))); + /* Check signature and bitfields + assert verify_indexed_attestation(state, convert_to_indexed(state, attestation)) */ + assertTrue(verify_indexed_attestation(state, convert_to_indexed(state, attestation))); } /* """ Process ``Attestation`` transaction. - Note that this function mutates ``state``. """ */ default void process_attestation(MutableBeaconState state, Attestation attestation) { - // Apply the attestation + AttestationData data = attestation.getData(); + SlotNumber attestation_slot = get_attestation_slot(state, data); + + /* Cache pending attestation + pending_attestation = PendingAttestation( + data=data, + aggregation_bitfield=attestation.aggregation_bitfield, + inclusion_delay=state.slot - attestation_slot, + proposer_index=get_beacon_proposer_index(state), + ) + if data.target_epoch == get_current_epoch(state): + state.current_epoch_attestations.append(pending_attestation) + else: + state.previous_epoch_attestations.append(pending_attestation) */ + PendingAttestation pending_attestation = new PendingAttestation( attestation.getAggregationBitfield(), - attestation.getData(), - attestation.getCustodyBitfield(), - state.getSlot() - ); - - if (slot_to_epoch(attestation.getData().getSlot()).equals(get_current_epoch(state))) { + data, + state.getSlot().minus(attestation_slot), + get_beacon_proposer_index(state)); + if (data.getTargetEpoch().equals(get_current_epoch(state))) { state.getCurrentEpochAttestations().add(pending_attestation); - } else if (slot_to_epoch(attestation.getData().getSlot()).equals(get_previous_epoch(state))) { + } else { state.getPreviousEpochAttestations().add(pending_attestation); } } + default void verify_deposit(BeaconState state, Deposit deposit) { + /* Verify the Merkle branch + assert verify_merkle_branch( + leaf=hash_tree_root(deposit.data), + proof=deposit.proof, + depth=DEPOSIT_CONTRACT_TREE_DEPTH, + index=deposit.index, + root=state.latest_eth1_data.deposit_root, + ) */ + assertTrue(verify_merkle_branch( + hash_tree_root(deposit.getData()), + deposit.getProof().listCopy(), + getConstants().getDepositContractTreeDepth(), + deposit.getIndex(), + state.getLatestEth1Data().getDepositRoot() + )); + } + + /* + def process_deposit(state: BeaconState, deposit: Deposit) -> None: + """ + Process an Eth1 deposit, registering a validator or increasing its balance. + """ + */ + default void process_deposit(MutableBeaconState state, Deposit deposit) { + /* Deposits must be processed in order + assert deposit.index == state.deposit_index + state.deposit_index += 1 */ + assertTrue(deposit.getIndex().equals(state.getDepositIndex())); + state.setDepositIndex(state.getDepositIndex().increment()); + + BLSPubkey pubkey = deposit.getData().getPubKey(); + Gwei amount = deposit.getData().getAmount(); + ValidatorIndex index = get_validator_index_by_pubkey(state, pubkey); + + /* if pubkey not in validator_pubkeys: */ + if (index.equals(ValidatorIndex.MAX)) { + /* Verify the deposit signature (proof of possession) + if not bls_verify(pubkey, signing_root(deposit.data), deposit.data.signature, get_domain(state, DOMAIN_DEPOSIT)): + return */ + if (isBlsVerifyProofOfPossession() && + !bls_verify( + pubkey, + signing_root(deposit.getData()), + deposit.getData().getSignature(), + get_domain(state, SignatureDomains.DEPOSIT)) + ) { + return; + } + + /* Add validator and balance entries + state.validator_registry.append(Validator( + pubkey=pubkey, + withdrawal_credentials=deposit.data.withdrawal_credentials, + activation_eligibility_epoch=FAR_FUTURE_EPOCH, + activation_epoch=FAR_FUTURE_EPOCH, + exit_epoch=FAR_FUTURE_EPOCH, + withdrawable_epoch=FAR_FUTURE_EPOCH, + effective_balance=min(amount - amount % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE) + )) + state.balances.append(amount) */ + state.getValidatorRegistry().add(new ValidatorRecord( + pubkey, + deposit.getData().getWithdrawalCredentials(), + getConstants().getFarFutureEpoch(), + getConstants().getFarFutureEpoch(), + getConstants().getFarFutureEpoch(), + getConstants().getFarFutureEpoch(), + Boolean.FALSE, + UInt64s.min( + amount.minus(Gwei.castFrom(amount.modulo(getConstants().getEffectiveBalanceIncrement()))), + getConstants().getMaxEffectiveBalance() + ) + )); + state.getBalances().add(amount); + } else { + /* Increase balance by deposit amount + index = validator_pubkeys.index(pubkey) + increase_balance(state, index, amount) */ + increase_balance(state, index, amount); + } + } + + default void verify_voluntary_exit(BeaconState state, VoluntaryExit exit) { + ValidatorRecord validator = state.getValidatorRegistry().get(exit.getValidatorIndex()); + + /* Verify the validator is active + assert is_active_validator(validator, get_current_epoch(state)) */ + assertTrue(is_active_validator(validator, get_current_epoch(state))); + + /* Verify the validator has not yet exited + assert validator.exit_epoch == FAR_FUTURE_EPOCH */ + assertTrue(validator.getExitEpoch().equals(getConstants().getFarFutureEpoch())); + + /* Exits must specify an epoch when they become valid; they are not valid before then + assert get_current_epoch(state) >= exit.epoch */ + assertTrue(get_current_epoch(state).greaterEqual(exit.getEpoch())); + + /* Verify the validator has been active long enough + assert get_current_epoch(state) - validator.activation_epoch >= PERSISTENT_COMMITTEE_PERIOD */ + assertTrue(get_current_epoch(state).minus(validator.getActivationEpoch()) + .greaterEqual(getConstants().getPersistentCommitteePeriod())); + + /* Verify signature + domain = get_domain(state, DOMAIN_VOLUNTARY_EXIT, exit.epoch) + assert bls_verify(validator.pubkey, signing_root(exit), exit.signature, domain) */ + UInt64 domain = get_domain(state, SignatureDomains.VOLUNTARY_EXIT, exit.getEpoch()); + assertTrue(bls_verify(validator.getPubKey(), signing_root(exit), exit.getSignature(), domain)); + } + /* """ Process ``VoluntaryExit`` transaction. - Note that this function mutates ``state``. """ */ default void process_voluntary_exit(MutableBeaconState state, VoluntaryExit exit) { initiate_validator_exit(state, exit.getValidatorIndex()); } + default void verify_transfer(BeaconState state, Transfer transfer) { + /* Verify the amount and fee are not individually too big (for anti-overflow purposes) + assert state.balances[transfer.sender] >= max(transfer.amount, transfer.fee) */ + assertTrue(state.getBalances().get(transfer.getSender()) + .greater(UInt64s.max(transfer.getAmount(), transfer.getFee()))); + + /* A transfer is valid in only one slot + assert state.slot == transfer.slot */ + assertTrue(state.getSlot().equals(transfer.getSlot())); + + /* Sender must be not yet eligible for activation, withdrawn, or transfer balance over MAX_EFFECTIVE_BALANCE + assert ( + state.validator_registry[transfer.sender].activation_eligibility_epoch == FAR_FUTURE_EPOCH or + get_current_epoch(state) >= state.validator_registry[transfer.sender].withdrawable_epoch or + transfer.amount + transfer.fee + MAX_EFFECTIVE_BALANCE <= state.balances[transfer.sender] + ) */ + assertTrue( + state.getValidatorRegistry().get(transfer.getSender()).getActivationEligibilityEpoch() + .equals(getConstants().getFarFutureEpoch()) + || get_current_epoch(state) + .greaterEqual(state.getValidatorRegistry().get(transfer.getSender()).getWithdrawableEpoch()) + || transfer.getAmount().plus(transfer.getFee()).plus(getConstants().getMaxEffectiveBalance()) + .lessEqual(state.getBalances().get(transfer.getSender())) + ); + + /* Verify that the pubkey is valid + assert ( + state.validator_registry[transfer.sender].withdrawal_credentials == + BLS_WITHDRAWAL_PREFIX_BYTE + hash(transfer.pubkey)[1:] + ) */ + assertTrue(state.getValidatorRegistry().get(transfer.getSender()).getWithdrawalCredentials() + .equals(getConstants().getBlsWithdrawalPrefixByte().concat(hash(transfer.getPubkey()).slice(1)))); + + /* Verify that the signature is valid + assert bls_verify(transfer.pubkey, signing_root(transfer), transfer.signature, get_domain(state, DOMAIN_TRANSFER)) */ + assertTrue(bls_verify( + transfer.getPubkey(), + signing_root(transfer), + transfer.getSignature(), + get_domain(state, SignatureDomains.TRANSFER)) + ); + } + /* """ Process ``Transfer`` transaction. - Note that this function mutates ``state``. """ */ default void process_transfer(MutableBeaconState state, Transfer transfer) { - // Process the transfer - state.getValidatorBalances().update(transfer.getSender(), - balance -> balance.minusSat(transfer.getAmount().plus(transfer.getFee()))); - state.getValidatorBalances().update(transfer.getRecipient(), - balance -> balance.plusSat(transfer.getAmount())); - state.getValidatorBalances().update(get_beacon_proposer_index(state, state.getSlot()), - balance -> balance.plusSat(transfer.getFee())); + /* Process the transfer + decrease_balance(state, transfer.sender, transfer.amount + transfer.fee) + increase_balance(state, transfer.recipient, transfer.amount) + increase_balance(state, get_beacon_proposer_index(state), transfer.fee) */ + decrease_balance(state, transfer.getSender(), transfer.getAmount().plus(transfer.getFee())); + increase_balance(state, transfer.getRecipient(), transfer.getAmount()); + increase_balance(state, get_beacon_proposer_index(state), transfer.getFee()); + + /* Verify balances are not dust + assert not (0 < state.balances[transfer.sender] < MIN_DEPOSIT_AMOUNT) + assert not (0 < state.balances[transfer.recipient] < MIN_DEPOSIT_AMOUNT) */ + assertTrue(!(state.getBalances().get(transfer.getSender()).greater(Gwei.ZERO) + && state.getBalances().get(transfer.getSender()).less(getConstants().getMinDepositAmount()))); + assertTrue(!(state.getBalances().get(transfer.getRecipient()).greater(Gwei.ZERO) + && state.getBalances().get(transfer.getRecipient()).less(getConstants().getMinDepositAmount()))); + } + + /* + def verify_block_state_root(state: BeaconState, block: BeaconBlock) -> None: + assert block.state_root == hash_tree_root(state) + */ + default void verify_block_state_root(BeaconState state, BeaconBlock block) { + assertTrue(block.getStateRoot().equals(hash_tree_root(state))); } } diff --git a/consensus/src/main/java/org/ethereum/beacon/consensus/spec/EpochProcessing.java b/consensus/src/main/java/org/ethereum/beacon/consensus/spec/EpochProcessing.java index 6a54c0a21..ed4e5f1ab 100644 --- a/consensus/src/main/java/org/ethereum/beacon/consensus/spec/EpochProcessing.java +++ b/consensus/src/main/java/org/ethereum/beacon/consensus/spec/EpochProcessing.java @@ -1,6 +1,5 @@ package org.ethereum.beacon.consensus.spec; -import static java.util.Collections.emptyList; import static java.util.stream.Collectors.toList; import java.util.ArrayList; @@ -8,15 +7,13 @@ import java.util.Collections; import java.util.Comparator; import java.util.List; -import java.util.stream.IntStream; -import java.util.stream.StreamSupport; +import java.util.stream.Collectors; import org.ethereum.beacon.core.BeaconState; import org.ethereum.beacon.core.MutableBeaconState; +import org.ethereum.beacon.core.operations.attestation.AttestationData; import org.ethereum.beacon.core.operations.attestation.Crosslink; -import org.ethereum.beacon.core.state.Eth1DataVote; import org.ethereum.beacon.core.state.HistoricalBatch; import org.ethereum.beacon.core.state.PendingAttestation; -import org.ethereum.beacon.core.state.ShardCommittee; import org.ethereum.beacon.core.state.ValidatorRecord; import org.ethereum.beacon.core.types.Bitfield64; import org.ethereum.beacon.core.types.EpochNumber; @@ -26,7 +23,6 @@ import org.ethereum.beacon.core.types.ValidatorIndex; import org.javatuples.Pair; import tech.pegasys.artemis.ethereum.core.Hash32; -import tech.pegasys.artemis.util.collections.ReadList; import tech.pegasys.artemis.util.uint.UInt64; import tech.pegasys.artemis.util.uint.UInt64s; @@ -34,987 +30,683 @@ * Per epoch processing. * * @see Per-epoch + * href="https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#per-epoch-processing">Per-epoch * processing in the spec. */ public interface EpochProcessing extends HelperFunction { /* - def get_current_total_balance(state: BeaconState) -> Gwei: - return get_total_balance(state, get_active_validator_indices(state.validator_registry, get_current_epoch(state))) + def get_total_active_balance(state: BeaconState) -> Gwei: + return get_total_balance(state, get_active_validator_indices(state, get_current_epoch(state))) */ - default Gwei get_current_total_balance(BeaconState state) { + default Gwei get_total_active_balance(BeaconState state) { return get_total_balance(state, - get_active_validator_indices(state.getValidatorRegistry(), get_current_epoch(state))); + get_active_validator_indices(state, get_current_epoch(state))); } /* - def get_previous_total_balance(state: BeaconState) -> Gwei: - return get_total_balance(state, get_active_validator_indices(state.validator_registry, get_previous_epoch(state))) + def get_matching_source_attestations(state: BeaconState, epoch: Epoch) -> List[PendingAttestation]: + assert epoch in (get_current_epoch(state), get_previous_epoch(state)) + return state.current_epoch_attestations if epoch == get_current_epoch(state) else state.previous_epoch_attestations */ - default Gwei get_previous_total_balance(BeaconState state) { - return get_total_balance(state, - get_active_validator_indices(state.getValidatorRegistry(), get_previous_epoch(state))); + default List get_matching_source_attestations(BeaconState state, EpochNumber epoch) { + assertTrue(epoch.equals(get_current_epoch(state)) || epoch.equals(get_previous_epoch(state))); + return epoch.equals(get_current_epoch(state)) ? + state.getCurrentEpochAttestations().listCopy() : state.getPreviousEpochAttestations().listCopy(); + } + + /* + def get_matching_target_attestations(state: BeaconState, epoch: Epoch) -> List[PendingAttestation]: + return [ + a for a in get_matching_source_attestations(state, epoch) + if a.data.target_root == get_block_root(state, epoch) + ] + */ + default List get_matching_target_attestations(BeaconState state, EpochNumber epoch) { + return get_matching_source_attestations(state, epoch).stream() + .filter(a -> a.getData().getTargetRoot().equals(get_block_root(state, epoch))) + .collect(toList()); + } + + /* + def get_matching_head_attestations(state: BeaconState, epoch: Epoch) -> List[PendingAttestation]: + return [ + a for a in get_matching_source_attestations(state, epoch) + if a.data.beacon_block_root == get_block_root_at_slot(state, get_attestation_slot(state, a)) + ] + */ + default List get_matching_head_attestations(BeaconState state, EpochNumber epoch) { + return get_matching_source_attestations(state, epoch).stream() + .filter(a -> a.getData().getBeaconBlockRoot().equals( + get_block_root_at_slot(state, get_attestation_slot(state, a.getData())))) + .collect(toList()); } /* - def get_attesting_indices(state: BeaconState, attestations: List[PendingAttestation]) -> List[ValidatorIndex]: + def get_unslashed_attesting_indices(state: BeaconState, attestations: List[PendingAttestation]) -> List[ValidatorIndex]: output = set() for a in attestations: - output = output.union(get_attestation_participants(state, a.data, a.aggregation_bitfield)) - return sorted(list(output)) + output = output.union(get_attesting_indices(state, a.data, a.aggregation_bitfield)) + return sorted(filter(lambda index: not state.validator_registry[index].slashed, list(output))) */ - default List get_attesting_indices(BeaconState state, List attestations) { - List output = new ArrayList<>(); - for (PendingAttestation a : attestations) { - output.addAll(get_attestation_participants(state, a.getData(), a.getAggregationBitfield())); - } - Collections.sort(output); - return output; + default List get_unslashed_attesting_indices(BeaconState state, List attestations) { + return attestations.stream() + .flatMap(a -> get_attesting_indices(state, a.getData(), a.getAggregationBitfield()).stream()) + .distinct() + .filter(i -> !state.getValidatorRegistry().get(i).getSlashed()) + .sorted() + .collect(Collectors.toList()); } /* def get_attesting_balance(state: BeaconState, attestations: List[PendingAttestation]) -> Gwei: - return get_total_balance(state, get_attesting_indices(state, attestations)) + return get_total_balance(state, get_unslashed_attesting_indices(state, attestations)) */ default Gwei get_attesting_balance(BeaconState state, List attestations) { - return get_total_balance(state, get_attesting_indices(state, attestations)); + return get_total_balance(state, get_unslashed_attesting_indices(state, attestations)); } /* - def get_current_epoch_boundary_attestations(state: BeaconState) -> List[PendingAttestation]: - return [ - a for a in state.current_epoch_attestations - if a.data.target_root == get_block_root(state, get_epoch_start_slot(get_current_epoch(state))) - ] + def get_crosslink_from_attestation_data(state: BeaconState, data: AttestationData) -> Crosslink: + return Crosslink( + epoch=min(data.target_epoch, state.current_crosslinks[data.shard].epoch + MAX_CROSSLINK_EPOCHS), + previous_crosslink_root=data.previous_crosslink_root, + crosslink_data_root=data.crosslink_data_root, + ) */ - default List get_current_epoch_boundary_attestations(BeaconState state) { - return state.getCurrentEpochAttestations().stream() - .filter(a -> a.getData() - .getTargetRoot() - .equals(get_block_root(state, get_epoch_start_slot(get_current_epoch(state))))) - .collect(toList()); + default Crosslink get_crosslink_from_attestation_data(BeaconState state, AttestationData data) { + return new Crosslink( + UInt64s.min( + data.getTargetEpoch(), + state.getCurrentCrosslinks().get(data.getShard()).getEpoch() + .plus(getConstants().getMaxCrosslinkEpochs())), + data.getPreviousCrosslinkRoot(), + data.getCrosslinkDataRoot() + ); } /* - def get_previous_epoch_boundary_attestations(state: BeaconState) -> List[PendingAttestation]: - return [ - a for a in state.previous_epoch_attestations - if a.data.target_root == get_block_root(state, get_epoch_start_slot(get_previous_epoch(state))) - ] + def get_attestations_for(crosslink: Crosslink) -> List[PendingAttestation]: + return [a for a in shard_attestations if get_crosslink_from_attestation_data(state, a.data) == crosslink] */ - default List get_previous_epoch_boundary_attestations(BeaconState state) { - return state.getPreviousEpochAttestations().stream() - .filter(a -> a.getData() - .getTargetRoot() - .equals(get_block_root(state, get_epoch_start_slot(get_previous_epoch(state))))) + default List get_attestations_for( + BeaconState state, List shard_attestations, Crosslink crosslink) { + return shard_attestations.stream() + .filter(a -> get_crosslink_from_attestation_data(state, a.getData()).equals(crosslink)) .collect(toList()); } /* - def get_previous_epoch_matching_head_attestations(state: BeaconState) -> List[PendingAttestation]: - return [ - a for a in state.previous_epoch_attestations - if a.data.beacon_block_root == get_block_root(state, a.data.slot) + def get_winning_crosslink_and_attesting_indices(state: BeaconState, epoch: Epoch, shard: Shard) -> Tuple[Crosslink, List[ValidatorIndex]]: + shard_attestations = [a for a in get_matching_source_attestations(state, epoch) if a.data.shard == shard] + shard_crosslinks = [get_crosslink_from_attestation_data(state, a.data) for a in shard_attestations] + candidate_crosslinks = [ + c for c in shard_crosslinks + if hash_tree_root(state.current_crosslinks[shard]) in (c.previous_crosslink_root, hash_tree_root(c)) ] - */ - default List get_previous_epoch_matching_head_attestations(BeaconState state) { - return state.getPreviousEpochAttestations().stream() - .filter(a -> a.getData() - .getBeaconBlockRoot() - .equals(get_block_root(state, a.getData().getSlot()))) - .collect(toList()); - } + if len(candidate_crosslinks) == 0: + return Crosslink(), [] - /* - def get_attestations_for(root) -> List[PendingAttestation]: - return [a for a in valid_attestations if a.data.crosslink_data_root == root] + def get_attestations_for(crosslink: Crosslink) -> List[PendingAttestation]: + return [a for a in shard_attestations if get_crosslink_from_attestation_data(state, a.data) == crosslink] + # Winning crosslink has the crosslink data root with the most balance voting for it (ties broken lexicographically) + winning_crosslink = max(candidate_crosslinks, key=lambda crosslink: ( + get_attesting_balance(state, get_attestations_for(crosslink)), crosslink.crosslink_data_root + )) + + return winning_crosslink, get_unslashed_attesting_indices(state, get_attestations_for(winning_crosslink)) */ - default Pair> get_winning_root_and_participants( - BeaconState state, SlotNumber slot, ShardNumber shard) { - ReadList attestations = - slot_to_epoch(slot).equals(get_current_epoch(state)) ? - state.getCurrentEpochAttestations() : state.getPreviousEpochAttestations(); - - List valid_attestations = - attestations.stream().filter(a -> a.getData().getShard().equals(shard)).collect(toList()); - List all_roots = - valid_attestations.stream().map(a -> a.getData().getCrosslinkDataRoot()).collect(toList()); - - // handle when no attestations for shard available - if (all_roots.isEmpty()) - return Pair.with(Hash32.ZERO, emptyList()); - - /* - def get_attestations_for(root) -> List[PendingAttestation]: - return [a for a in valid_attestations if a.data.crosslink_data_root == root] - */ - - // Winning crosslink root is the root with the most votes for it, ties broken in favor of - // lexicographically higher hash - // winning_root = max(all_roots, key=lambda r: (get_attesting_balance(state, get_attestations_for(r)), r)) - Hash32 winning_root = all_roots.stream().max((r1, r2) -> { - Gwei balance_r1 = get_attesting_balance(state, valid_attestations.stream() - .filter(a -> a.getData().getCrosslinkDataRoot().equals(r1)) - .collect(toList())); - - Gwei balance_r2 = get_attesting_balance(state, valid_attestations.stream() - .filter(a -> a.getData().getCrosslinkDataRoot().equals(r1)) - .collect(toList())); - - if (balance_r1.equals(balance_r2)) { - return r1.toString().compareTo(r2.toString()); - } else { - return balance_r1.compareTo(balance_r2); - } - }).get(); - - /* - return winning_root, get_attesting_indices(state, get_attestations_for(winning_root)) - */ - return Pair.with( - winning_root, - get_attesting_indices(state, valid_attestations.stream() - .filter(a -> a.getData().getCrosslinkDataRoot().equals(winning_root)) - .collect(toList()))); + default Pair> get_winning_crosslink_and_attesting_indices( + BeaconState state, EpochNumber epoch, ShardNumber shard) { + List shard_attestations = get_matching_source_attestations(state, epoch) + .stream().filter(a -> a.getData().getShard().equals(shard)).collect(toList()); + List shard_crosslinks = shard_attestations.stream() + .map(a -> get_crosslink_from_attestation_data(state, a.getData())).collect(toList()); + List candidate_crosslinks = shard_crosslinks.stream() + .filter(c -> { + Hash32 root = hash_tree_root(state.getCurrentCrosslinks().get(shard)); + return root.equals(c.getPreviousCrosslinkRoot()) || root.equals(hash_tree_root(c)); + }).collect(toList()); + if (candidate_crosslinks.isEmpty()) { + return Pair.with(new Crosslink(getConstants().getGenesisEpoch(), Hash32.ZERO, Hash32.ZERO), + Collections.emptyList()); + } + + Crosslink winning_crosslink = candidate_crosslinks.stream() + .max((c1, c2) -> { + Gwei b1 = get_attesting_balance(state, get_attestations_for(state, shard_attestations, c1)); + Gwei b2 = get_attesting_balance(state, get_attestations_for(state, shard_attestations, c2)); + if (b1.equals(b2)) { + return c1.getCrosslinkDataRoot().toString().compareTo(c2.getCrosslinkDataRoot().toString()); + } else { + return b1.compareTo(b2); + } + }).get(); + + return Pair.with(winning_crosslink, + get_unslashed_attesting_indices(state, + get_attestations_for(state, shard_attestations, winning_crosslink))); } /* - def earliest_attestation(state: BeaconState, validator_index: ValidatorIndex) -> PendingAttestation: + def get_earliest_attestation(state: BeaconState, attestations: List[PendingAttestation], index: ValidatorIndex) -> PendingAttestation: return min([ - a for a in state.previous_epoch_attestations if - validator_index in get_attestation_participants(state, a.data, a.aggregation_bitfield) + a for a in attestations if index in get_attesting_indices(state, a.data, a.aggregation_bitfield) ], key=lambda a: a.inclusion_slot) */ - default PendingAttestation earliest_attestation(BeaconState state, ValidatorIndex validatorIndex) { - return state.getPreviousEpochAttestations().stream() - .filter(a -> get_attestation_participants(state, a.getData(), a.getAggregationBitfield()) - .contains(validatorIndex)) - .min(Comparator.comparing(PendingAttestation::getInclusionSlot)) + default PendingAttestation get_earliest_attestation(BeaconState state, List attestations, ValidatorIndex index) { + return attestations.stream() + .filter(a -> get_attesting_indices(state, a.getData(), a.getAggregationBitfield()).contains(index)) + .min(Comparator.comparing(PendingAttestation::getInclusionDelay)) .get(); } - /* - def inclusion_slot(state: BeaconState, validator_index: ValidatorIndex) -> Slot: - return earliest_attestation(state, validator_index).inclusion_slot - */ - default SlotNumber inclusion_slot(BeaconState state, ValidatorIndex validatorIndex) { - return earliest_attestation(state, validatorIndex).getInclusionSlot(); - } /* - def inclusion_distance(state: BeaconState, validator_index: ValidatorIndex) -> int: - attestation = earliest_attestation(state, validator_index) - return attestation.inclusion_slot - attestation.data.slot + def process_justification_and_finalization(state: BeaconState) -> None: + if get_current_epoch(state) <= GENESIS_EPOCH + 1: + return */ - default SlotNumber inclusion_distance(BeaconState state, ValidatorIndex validatorIndex) { - PendingAttestation attestation = earliest_attestation(state, validatorIndex); - return attestation.getInclusionSlot().minus(attestation.getData().getSlot()); - } + default void process_justification_and_finalization(MutableBeaconState state) { + if (get_current_epoch(state).lessEqual(getConstants().getGenesisEpoch().increment())) { + return; + } - /* - Note: this function mutates beacon state - */ - default void update_justification_and_finalization(MutableBeaconState state) { - /* - new_justified_epoch = state.current_justified_epoch - new_finalized_epoch = state.finalized_epoch - */ - EpochNumber new_justified_epoch = state.getCurrentJustifiedEpoch(); - EpochNumber new_finalized_epoch = state.getFinalizedEpoch(); - - // Rotate the justification bitfield up one epoch to make room for the current epoch + EpochNumber previous_epoch = get_previous_epoch(state); + EpochNumber current_epoch = get_current_epoch(state); + EpochNumber old_previous_justified_epoch = state.getPreviousJustifiedEpoch(); + EpochNumber old_current_justified_epoch = state.getCurrentJustifiedEpoch(); + + /* Process justifications + state.previous_justified_epoch = state.current_justified_epoch + state.previous_justified_root = state.current_justified_root + state.justification_bitfield = (state.justification_bitfield << 1) % 2**64 */ + state.setPreviousJustifiedEpoch(state.getCurrentJustifiedEpoch()); + state.setPreviousJustifiedRoot(state.getCurrentJustifiedRoot()); state.setJustificationBitfield(state.getJustificationBitfield().shl(1)); - /* - # If the previous epoch gets justified, fill the second last bit - - previous_boundary_attesting_balance = get_attesting_balance(state, get_previous_epoch_boundary_attestations(state)) - if previous_boundary_attesting_balance * 3 >= get_previous_total_balance(state) * 2: - new_justified_epoch = get_current_epoch(state) - 1 - state.justification_bitfield |= 2 - */ - Gwei previous_boundary_attesting_balance = get_attesting_balance(state, - get_previous_epoch_boundary_attestations(state)); - if (previous_boundary_attesting_balance.times(3) - .greaterEqual(get_previous_total_balance(state).times(2))) { - new_justified_epoch = get_current_epoch(state).decrement(); + /* previous_epoch_matching_target_balance = get_attesting_balance(state, get_matching_target_attestations(state, previous_epoch)) + if previous_epoch_matching_target_balance * 3 >= get_total_active_balance(state) * 2: + state.current_justified_epoch = previous_epoch + state.current_justified_root = get_block_root(state, state.current_justified_epoch) + state.justification_bitfield |= (1 << 1) */ + Gwei previous_epoch_matching_target_balance = + get_attesting_balance(state, get_matching_target_attestations(state, previous_epoch)); + if (previous_epoch_matching_target_balance.times(3) + .greaterEqual(get_total_active_balance(state).times(2))) { + state.setCurrentJustifiedEpoch(previous_epoch); + state.setCurrentJustifiedRoot(get_block_root(state, state.getCurrentJustifiedEpoch())); state.setJustificationBitfield(state.getJustificationBitfield().or(2)); } - /* - # If the current epoch gets justified, fill the last bit - - current_boundary_attesting_balance = get_attesting_balance(state, get_current_epoch_boundary_attestations(state)) - if current_boundary_attesting_balance * 3 >= get_current_total_balance(state) * 2: - new_justified_epoch = get_current_epoch(state) - state.justification_bitfield |= 1 - */ - Gwei current_boundary_attesting_balance = - get_attesting_balance(state, get_current_epoch_boundary_attestations(state)); - if (current_boundary_attesting_balance.times(3).greaterEqual(get_current_total_balance(state).times(2))) { - new_justified_epoch = get_current_epoch(state); + /* current_epoch_matching_target_balance = get_attesting_balance(state, get_matching_target_attestations(state, current_epoch)) + if current_epoch_matching_target_balance * 3 >= get_total_active_balance(state) * 2: + state.current_justified_epoch = current_epoch + state.current_justified_root = get_block_root(state, state.current_justified_epoch) + state.justification_bitfield |= (1 << 0) */ + Gwei current_epoch_matching_target_balance = + get_attesting_balance(state, get_matching_target_attestations(state, current_epoch)); + if (current_epoch_matching_target_balance.times(3) + .greaterEqual(get_total_active_balance(state).times(2))) { + state.setCurrentJustifiedEpoch(current_epoch); + state.setCurrentJustifiedRoot(get_block_root(state, state.getCurrentJustifiedEpoch())); state.setJustificationBitfield(state.getJustificationBitfield().or(1)); } - // Process finalizations - - /* - bitfield = state.justification_bitfield - current_epoch = get_current_epoch(state) - */ + /* Process finalizations + bitfield = state.justification_bitfield */ Bitfield64 bitfield = state.getJustificationBitfield(); - EpochNumber current_epoch = get_current_epoch(state); - /* - # The 2nd/3rd/4th most recent epochs are all justified, the 2nd using the 4th as source - if (bitfield >> 1) % 8 == 0b111 and state.previous_justified_epoch == current_epoch - 3: - new_finalized_epoch = state.previous_justified_epoch */ - if (((bitfield.getValue() >>> 1) % 8 == 0b111L) - && (state.getPreviousJustifiedEpoch().equals(current_epoch.minus(3)))) { - new_finalized_epoch = state.getPreviousJustifiedEpoch(); + /* The 2nd/3rd/4th most recent epochs are justified, the 2nd using the 4th as source + if (bitfield >> 1) % 8 == 0b111 and old_previous_justified_epoch == current_epoch - 3: + state.finalized_epoch = old_previous_justified_epoch + state.finalized_root = get_block_root(state, state.finalized_epoch) */ + if ((bitfield.getValue() >>> 1) % 8 == 0b111 && old_previous_justified_epoch.equals(current_epoch.minus(3))) { + state.setFinalizedEpoch(old_current_justified_epoch); + state.setFinalizedRoot(get_block_root(state, state.getFinalizedEpoch())); } - /* - # The 2nd/3rd most recent epochs are both justified, the 2nd using the 3rd as source - if (bitfield >> 1) % 4 == 0b11 and state.previous_justified_epoch == current_epoch - 2: - new_finalized_epoch = state.previous_justified_epoch */ - if (((bitfield.getValue() >>> 1) % 4 == 0b11L) - && (state.getPreviousJustifiedEpoch().equals(current_epoch.minus(2)))) { - new_finalized_epoch = state.getPreviousJustifiedEpoch(); + /* The 2nd/3rd most recent epochs are justified, the 2nd using the 3rd as source + if (bitfield >> 1) % 4 == 0b11 and old_previous_justified_epoch == current_epoch - 2: + state.finalized_epoch = old_previous_justified_epoch + state.finalized_root = get_block_root(state, state.finalized_epoch) */ + if ((bitfield.getValue() >>> 1) % 4 == 0b11 && old_previous_justified_epoch.equals(current_epoch.minus(2))) { + state.setFinalizedEpoch(old_current_justified_epoch); + state.setFinalizedRoot(get_block_root(state, state.getFinalizedEpoch())); } - /* - # The 1st/2nd/3rd most recent epochs are all justified, the 1st using the 3rd as source - if (bitfield >> 0) % 8 == 0b111 and state.current_justified_epoch == current_epoch - 2: - new_finalized_epoch = state.current_justified_epoch */ - if (((bitfield.getValue() >>> 0) % 8 == 0b111L) - && (state.getCurrentJustifiedEpoch().equals(current_epoch.minus(2)))) { - new_finalized_epoch = state.getCurrentJustifiedEpoch(); - } - - /* - # The 1st/2nd most recent epochs are both justified, the 1st using the 2nd as source - if (bitfield >> 0) % 4 == 0b11 and state.current_justified_epoch == current_epoch - 1: - new_finalized_epoch = state.current_justified_epoch */ - if (((bitfield.getValue() >>> 0) % 4 == 0b11L) - && (state.getCurrentJustifiedEpoch().equals(current_epoch.minus(1)))) { - new_finalized_epoch = state.getCurrentJustifiedEpoch(); - } - - // Update state jusification/finality fields - - /* - state.previous_justified_epoch = state.current_justified_epoch - state.previous_justified_root = state.current_justified_root */ - state.setPreviousJustifiedEpoch(state.getCurrentJustifiedEpoch()); - state.setPreviousJustifiedRoot(state.getCurrentJustifiedRoot()); - - /* - if new_justified_epoch != state.current_justified_epoch: - state.current_justified_epoch = new_justified_epoch - state.current_justified_root = get_block_root(state, get_epoch_start_slot(new_justified_epoch)) */ - if (!new_justified_epoch.equals(state.getCurrentJustifiedEpoch())) { - state.setCurrentJustifiedEpoch(new_justified_epoch); - state.setCurrentJustifiedRoot(get_block_root(state, get_epoch_start_slot(new_justified_epoch))); + /* The 1st/2nd/3rd most recent epochs are justified, the 1st using the 3rd as source + if (bitfield >> 0) % 8 == 0b111 and old_current_justified_epoch == current_epoch - 2: + state.finalized_epoch = old_current_justified_epoch + state.finalized_root = get_block_root(state, state.finalized_epoch) */ + if (bitfield.getValue() % 8 == 0b111 && old_previous_justified_epoch.equals(current_epoch.minus(2))) { + state.setFinalizedEpoch(old_current_justified_epoch); + state.setFinalizedRoot(get_block_root(state, state.getFinalizedEpoch())); } - /* - if new_finalized_epoch != state.finalized_epoch: - state.finalized_epoch = new_finalized_epoch - state.finalized_root = get_block_root(state, get_epoch_start_slot(new_finalized_epoch)) */ - if (!new_finalized_epoch.equals(state.getFinalizedEpoch())) { - state.setFinalizedEpoch(new_finalized_epoch); - state.setFinalizedRoot(get_block_root(state, get_epoch_start_slot(new_finalized_epoch))); + /* The 1st/2nd most recent epochs are justified, the 1st using the 2nd as source + if (bitfield >> 0) % 4 == 0b11 and old_current_justified_epoch == current_epoch - 1: + state.finalized_epoch = old_current_justified_epoch + state.finalized_root = get_block_root(state, state.finalized_epoch) */ + if (bitfield.getValue() % 4 == 0b11 && old_previous_justified_epoch.equals(current_epoch.minus(1))) { + state.setFinalizedEpoch(old_current_justified_epoch); + state.setFinalizedRoot(get_block_root(state, state.getFinalizedEpoch())); } } /* - Note: this function mutates beacon state. + def process_crosslinks(state: BeaconState) -> None: + state.previous_crosslinks = [c for c in state.current_crosslinks] + for epoch in (get_previous_epoch(state), get_current_epoch(state)): + for offset in range(get_epoch_committee_count(state, epoch)): + shard = (get_epoch_start_shard(state, epoch) + offset) % SHARD_COUNT + crosslink_committee = get_crosslink_committee(state, epoch, shard) + winning_crosslink, attesting_indices = get_winning_crosslink_and_attesting_indices(state, epoch, shard) + if 3 * get_total_balance(state, attesting_indices) >= 2 * get_total_balance(state, crosslink_committee): + state.current_crosslinks[shard] = winning_crosslink */ default void process_crosslinks(MutableBeaconState state) { - EpochNumber current_epoch = get_current_epoch(state); - EpochNumber previous_epoch = - UInt64s.max(current_epoch.decrement(), getConstants().getGenesisEpoch()); - EpochNumber next_epoch = current_epoch.increment(); - - // swap previous crosslinks state.getPreviousCrosslinks().clear(); state.getPreviousCrosslinks().addAll(state.getCurrentCrosslinks().listCopy()); - for (SlotNumber slot : get_epoch_start_slot(previous_epoch) - .iterateTo(get_epoch_start_slot(next_epoch))) { - List committees_at_slot = get_crosslink_committees_at_slot(state, slot); - for (ShardCommittee shard_and_committee : committees_at_slot) { - Pair> root_and_participants = - get_winning_root_and_participants(state, slot, shard_and_committee.getShard()); - Gwei participating_balance = get_total_balance(state, root_and_participants.getValue1()); - Gwei total_balance = get_total_balance(state, shard_and_committee.getCommittee()); - - if (participating_balance.times(3).greaterEqual(total_balance.times(2))) { - state.getCurrentCrosslinks().set(shard_and_committee.getShard(), new Crosslink( - slot_to_epoch(slot), - root_and_participants.getValue0() - )); + for (EpochNumber epoch : get_previous_epoch(state).iterateTo(get_current_epoch(state))) { + for (UInt64 offset : UInt64s.iterate(UInt64.ZERO, get_epoch_committee_count(state, epoch))) { + ShardNumber shard = get_epoch_start_shard(state, epoch) + .plusModulo(offset, getConstants().getShardCount()); + List crosslink_committee = get_crosslink_committee(state, epoch, shard); + Pair> winner = + get_winning_crosslink_and_attesting_indices(state, epoch, shard); + Crosslink winning_crosslink = winner.getValue0(); + List attesting_indices = winner.getValue1(); + if (get_total_balance(state, attesting_indices).times(3) + .greaterEqual(get_total_balance(state, crosslink_committee).times(2))) { + state.getCurrentCrosslinks().set(shard, winning_crosslink); } - } - } - } - - /* - Note: this function mutates beacon state - - def maybe_reset_eth1_period(state: BeaconState) -> None: - if (get_current_epoch(state) + 1) % EPOCHS_PER_ETH1_VOTING_PERIOD == 0: - for eth1_data_vote in state.eth1_data_votes: - # If a majority of all votes were for a particular eth1_data value, - # then set that as the new canonical value - if eth1_data_vote.vote_count * 2 > EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH: - state.latest_eth1_data = eth1_data_vote.eth1_data - state.eth1_data_votes = [] - */ - default void maybe_reset_eth1_period(MutableBeaconState state) { - if (get_current_epoch(state).increment().modulo(getConstants().getEpochsPerEth1VotingPeriod()) - .equals(EpochNumber.ZERO)) { - for (Eth1DataVote eth1_data_vote : state.getEth1DataVotes()) { - // If a majority of all votes were for a particular eth1_data value, - // then set that as the new canonical value - if (eth1_data_vote.getVoteCount().times(2) - .compareTo(getConstants().getEpochsPerEth1VotingPeriod().times(getConstants().getSlotsPerEpoch())) > 0) { - state.setLatestEth1Data(eth1_data_vote.getEth1Data()); - } - } - state.getEth1DataVotes().clear(); + }; } } /* def get_base_reward(state: BeaconState, index: ValidatorIndex) -> Gwei: - if get_previous_total_balance(state) == 0: + adjusted_quotient = integer_squareroot(get_total_active_balance(state)) // BASE_REWARD_QUOTIENT + if adjusted_quotient == 0: return 0 - - adjusted_quotient = integer_squareroot(get_previous_total_balance(state)) // BASE_REWARD_QUOTIENT - return get_effective_balance(state, index) // adjusted_quotient // 5 + return state.validator_registry[index].effective_balance // adjusted_quotient // BASE_REWARDS_PER_EPOCH */ default Gwei get_base_reward(BeaconState state, ValidatorIndex index) { - Gwei previous_total_balance = get_previous_total_balance(state); - if (previous_total_balance.equals(Gwei.ZERO)) { + UInt64 adjusted_quotient = integer_squareroot(get_total_active_balance(state)) + .dividedBy(getConstants().getBaseRewardQuotient()); + if (adjusted_quotient.equals(UInt64.ZERO)) { return Gwei.ZERO; } - - UInt64 adjusted_quotient = integer_squareroot(previous_total_balance) - .dividedBy(getConstants().getBaseRewardQuotient()); - return get_effective_balance(state, index).dividedBy(adjusted_quotient).dividedBy(5); + return state.getValidatorRegistry().get(index).getEffectiveBalance() + .dividedBy(adjusted_quotient).dividedBy(getConstants().getBaseRewardsPerEpoch()); } /* - def get_inactivity_penalty(state: BeaconState, index: ValidatorIndex, epochs_since_finality: int) -> Gwei: - return ( - get_base_reward(state, index) + - get_effective_balance(state, index) * epochs_since_finality // INACTIVITY_PENALTY_QUOTIENT // 2 - ) + def get_attestation_deltas(state: BeaconState) -> Tuple[List[Gwei], List[Gwei]]: */ - default Gwei get_inactivity_penalty(BeaconState state, ValidatorIndex index, EpochNumber epochsSinceFinality) { - return get_base_reward(state, index).plus( - get_effective_balance(state, index) - .times(epochsSinceFinality).dividedBy(getConstants().getInactivityPenaltyQuotient()).dividedBy(2) - ); - } - - /* - When blocks are finalizing normally... - - # deltas[0] for rewards - # deltas[1] for penalties - */ - default Gwei[][] compute_normal_justification_and_finalization_deltas(BeaconState state) { - /* - deltas = [ - [0 for index in range(len(state.validator_registry))], - [0 for index in range(len(state.validator_registry))] - ] */ - Gwei[][] deltas = { - new Gwei[state.getValidatorRegistry().size().getIntValue()], - new Gwei[state.getValidatorRegistry().size().getIntValue()] - }; - Arrays.fill(deltas[0], Gwei.ZERO); - Arrays.fill(deltas[1], Gwei.ZERO); - - // Some helper variables - List previous_epoch_attestations = - state.getPreviousEpochAttestations().listCopy(); - List boundary_attestations = get_previous_epoch_boundary_attestations(state); - Gwei boundary_attesting_balance = get_attesting_balance(state, boundary_attestations); - Gwei total_balance = get_previous_total_balance(state); - Gwei total_attesting_balance = get_attesting_balance(state, previous_epoch_attestations); - List matching_head_attestations = - get_previous_epoch_matching_head_attestations(state); - Gwei matching_head_balance = get_attesting_balance(state, matching_head_attestations); - - // Process rewards or penalties for all validators - List active_validator_indices = - get_active_validator_indices(state.getValidatorRegistry(), get_previous_epoch(state)); - for (ValidatorIndex index : active_validator_indices) { - int i = index.getIntValue(); - // Expected FFG source - - /* if index in get_attesting_indices(state, state.previous_epoch_attestations): - deltas[0][index] += get_base_reward(state, index) * total_attesting_balance // total_balance - # Inclusion speed bonus - deltas[0][index] += ( - get_base_reward(state, index) * MIN_ATTESTATION_INCLUSION_DELAY // - inclusion_distance(state, index) - ) */ - if (get_attesting_indices(state, previous_epoch_attestations).contains(index)) { - deltas[0][i] = deltas[0][i].plus( - get_base_reward(state, index).mulDiv(total_attesting_balance, total_balance)); - // Inclusion speed bonus - deltas[0][i] = deltas[0][i].plus( - get_base_reward(state, index) - .mulDiv(Gwei.castFrom(getConstants().getMinAttestationInclusionDelay()), - Gwei.castFrom(inclusion_distance(state, index)))); - } else { - /* else: - deltas[1][index] += get_base_reward(state, index) */ - deltas[1][i] = deltas[1][i].plus(get_base_reward(state, index)); - } - - // Expected FFG target - - /* if index in get_attesting_indices(state, boundary_attestations): - deltas[0][index] += get_base_reward(state, index) * boundary_attesting_balance // total_balance - else: - deltas[1][index] += get_base_reward(state, index) */ - if (get_attesting_indices(state, boundary_attestations).contains(index)) { - deltas[0][i] = deltas[0][i].plus( - get_base_reward(state, index).mulDiv(boundary_attesting_balance, total_balance)); - } else { - deltas[1][i] = deltas[1][i].plus(get_base_reward(state, index)); - } - - // Expected head - - /* if index in get_attesting_indices(state, matching_head_attestations): - deltas[0][index] += get_base_reward(state, index) * matching_head_balance // total_balance - else: - deltas[1][index] += get_base_reward(state, index) */ - if (get_attesting_indices(state, matching_head_attestations).contains(index)) { - deltas[0][i] = deltas[0][i].plus( - get_base_reward(state, index).mulDiv(matching_head_balance, total_balance)); - } else { - deltas[1][i] = deltas[1][i].plus(get_base_reward(state, index)); - } - - // Proposer bonus - /* if index in get_attesting_indices(state, state.previous_epoch_attestations): - proposer_index = get_beacon_proposer_index(state, inclusion_slot(state, index)) - deltas[0][proposer_index] += get_base_reward(state, index) // ATTESTATION_INCLUSION_REWARD_QUOTIENT */ - if (get_attesting_indices(state, previous_epoch_attestations).contains(index)) { - ValidatorIndex proposer_index = get_beacon_proposer_index(state, inclusion_slot(state, index)); - deltas[0][proposer_index.getIntValue()] = deltas[0][proposer_index.getIntValue()].plus( - get_base_reward(state, index).dividedBy(getConstants().getAttestationInclusionRewardQuotient())); + default Gwei[][] get_attestation_deltas(BeaconState state) { + EpochNumber previous_epoch = get_previous_epoch(state); + Gwei total_balance = get_total_active_balance(state); + Gwei[] rewards = new Gwei[state.getValidatorRegistry().size().getIntValue()]; + Gwei[] penalties = new Gwei[state.getValidatorRegistry().size().getIntValue()]; + Arrays.fill(rewards, Gwei.ZERO); + Arrays.fill(penalties, Gwei.ZERO); + + List eligible_validator_indices = new ArrayList<>(); + for (ValidatorIndex index : state.getValidatorRegistry().size()) { + ValidatorRecord validator = state.getValidatorRegistry().get(index); + if (is_active_validator(validator, previous_epoch) + && (validator.getSlashed() && previous_epoch.increment().less(validator.getWithdrawableEpoch()))) { + eligible_validator_indices.add(index); } } - return deltas; - } - - /* - When blocks are not finalizing normally... - - # deltas[0] for rewards - # deltas[1] for penalties - */ - default Gwei[][] compute_inactivity_leak_deltas(BeaconState state) { - /* - deltas = [ - [0 for index in range(len(state.validator_registry))], - [0 for index in range(len(state.validator_registry))] - ] */ - Gwei[][] deltas = { - new Gwei[state.getValidatorRegistry().size().getIntValue()], - new Gwei[state.getValidatorRegistry().size().getIntValue()] - }; - Arrays.fill(deltas[0], Gwei.ZERO); - Arrays.fill(deltas[1], Gwei.ZERO); - - List previous_epoch_attestations = - state.getPreviousEpochAttestations().listCopy(); - List boundary_attestations = - get_previous_epoch_boundary_attestations(state); - List matching_head_attestations = - get_previous_epoch_matching_head_attestations(state); - List active_validator_indices = - get_active_validator_indices(state.getValidatorRegistry(), get_previous_epoch(state)); - EpochNumber epochs_since_finality = - get_current_epoch(state).increment().minus(state.getFinalizedEpoch()); - - // for index in active_validator_indices: - for (ValidatorIndex index : active_validator_indices) { - int i = index.getIntValue(); - - /* if index not in get_attesting_indices(state, state.previous_epoch_attestations): - deltas[1][index] += get_inactivity_penalty(state, index, epochs_since_finality) - else: - # If a validator did attest, apply a small penalty for getting attestations included late - deltas[0][index] += ( - get_base_reward(state, index) * MIN_ATTESTATION_INCLUSION_DELAY // - inclusion_distance(state, index) - ) - deltas[1][index] += get_base_reward(state, index) */ - if (!get_attesting_indices(state, previous_epoch_attestations).contains(index)) { - deltas[1][i] = deltas[1][i].plus( - get_inactivity_penalty(state, index, epochs_since_finality)); - } else { - // If a validator did attest, apply a small penalty for getting attestations included late - deltas[0][i] = deltas[0][i].plus( - get_base_reward(state, index).mulDiv( - Gwei.castFrom(getConstants().getMinAttestationInclusionDelay()), - Gwei.castFrom(inclusion_distance(state, index)))); - deltas[1][i] = deltas[1][i].plus(get_base_reward(state, index)); - } - - /* if index not in get_attesting_indices(state, boundary_attestations): - deltas[1][index] += get_inactivity_penalty(state, index, epochs_since_finality) */ - if (!get_attesting_indices(state, boundary_attestations).contains(index)) { - deltas[1][i] = deltas[1][i].plus(get_inactivity_penalty(state, index, epochs_since_finality)); - } - /* if index not in get_attesting_indices(state, matching_head_attestations): - deltas[1][index] += get_base_reward(state, index) */ - if (!get_attesting_indices(state, matching_head_attestations).contains(index)) { - deltas[1][i] = deltas[1][i].plus(get_base_reward(state, index)); + /* Micro-incentives for matching FFG source, FFG target, and head + matching_source_attestations = get_matching_source_attestations(state, previous_epoch) + matching_target_attestations = get_matching_target_attestations(state, previous_epoch) + matching_head_attestations = get_matching_head_attestations(state, previous_epoch) */ + List matching_source_attestations = get_matching_source_attestations(state, previous_epoch); + List matching_target_attestations = get_matching_target_attestations(state, previous_epoch); + List matching_head_attestations = get_matching_head_attestations(state, previous_epoch); + + /* for attestations in (matching_source_attestations, matching_target_attestations, matching_head_attestations): + unslashed_attesting_indices = get_unslashed_attesting_indices(state, attestations) + attesting_balance = get_attesting_balance(state, attestations) + for index in eligible_validator_indices: + if index in unslashed_attesting_indices: + rewards[index] += get_base_reward(state, index) * attesting_balance // total_balance + else: + penalties[index] += get_base_reward(state, index) */ + for (List attestations : + Arrays.asList(matching_source_attestations, matching_target_attestations, matching_head_attestations)) { + List unslashed_attesting_indices = get_unslashed_attesting_indices(state, attestations); + Gwei attesting_balance = get_attesting_balance(state, attestations); + for (ValidatorIndex index : eligible_validator_indices) { + if (unslashed_attesting_indices.contains(index)) { + rewards[index.getIntValue()] = rewards[index.getIntValue()] + .plus(get_base_reward(state, index).times(attesting_balance).dividedBy(total_balance)); + } else { + penalties[index.getIntValue()] = penalties[index.getIntValue()] + .plus(get_base_reward(state, index)); + } } } - // Penalize slashed-but-inactive validators as though they were active but offline + /* Proposer and inclusion delay micro-rewards + for index in get_unslashed_attesting_indices(state, matching_source_attestations): + attestation = min([ + a for a in matching_source_attestations + if index in get_attesting_indices(state, a.data, a.aggregation_bitfield) + ], key=lambda a: a.inclusion_delay) + rewards[attestation.proposer_index] += get_base_reward(state, index) // PROPOSER_REWARD_QUOTIENT + rewards[index] += get_base_reward(state, index) * MIN_ATTESTATION_INCLUSION_DELAY // attestation.inclusion_delay */ + for (ValidatorIndex index : get_unslashed_attesting_indices(state, matching_source_attestations)) { + PendingAttestation attestation = + matching_source_attestations.stream() + .filter(a -> get_attesting_indices(state, a.getData(), a.getAggregationBitfield()).contains(index)) + .min(Comparator.comparing(PendingAttestation::getInclusionDelay)) + .get(); + rewards[attestation.getProposerIndex().getIntValue()] = rewards[attestation.getProposerIndex().getIntValue()] + .plus(get_base_reward(state, index).dividedBy(getConstants().getProposerRewardQuotient())); + rewards[index.getIntValue()] = rewards[index.getIntValue()] + .plus(get_base_reward(state, index) + .times(getConstants().getMinAttestationInclusionDelay()) + .dividedBy(attestation.getInclusionDelay())); + } - // for index in range(len(state.validator_registry)): - for (ValidatorIndex index : state.getValidatorRegistry().size()) { - /* eligible = ( - index not in active_validator_indices and - state.validator_registry[index].slashed and - get_current_epoch(state) < state.validator_registry[index].withdrawable_epoch - ) */ - boolean eligible = !active_validator_indices.contains(index) && - state.getValidatorRegistry().get(index).getSlashed() && - get_current_epoch(state).less(state.getValidatorRegistry().get(index).getWithdrawableEpoch()); - - /* if eligible: - deltas[1][index] += ( - 2 * get_inactivity_penalty(state, index, epochs_since_finality) + - get_base_reward(state, index) - ) */ - if (eligible) { - deltas[1][index.getIntValue()] = deltas[1][index.getIntValue()].plus( - get_inactivity_penalty(state, index, epochs_since_finality).times(2) - .plus(get_base_reward(state, index))); + /* Inactivity penalty + finality_delay = previous_epoch - state.finalized_epoch + if finality_delay > MIN_EPOCHS_TO_INACTIVITY_PENALTY: + matching_target_attesting_indices = get_unslashed_attesting_indices(state, matching_target_attestations) + for index in eligible_validator_indices: + penalties[index] += BASE_REWARDS_PER_EPOCH * get_base_reward(state, index) + if index not in matching_target_attesting_indices: + penalties[index] += state.validator_registry[index].effective_balance * finality_delay // INACTIVITY_PENALTY_QUOTIENT */ + EpochNumber finality_delay = previous_epoch.minus(state.getFinalizedEpoch()); + if (finality_delay.greater(getConstants().getMinEpochsToInactivityPenalty())) { + List matching_target_attesting_indices = get_unslashed_attesting_indices(state, matching_target_attestations); + for (ValidatorIndex index : eligible_validator_indices) { + penalties[index.getIntValue()] = penalties[index.getIntValue()] + .plus(get_base_reward(state, index).times(getConstants().getBaseRewardsPerEpoch())); + if (!matching_target_attesting_indices.contains(index)) { + penalties[index.getIntValue()] = penalties[index.getIntValue()] + .plus(state.getValidatorRegistry().get(index).getEffectiveBalance() + .times(finality_delay).dividedBy(getConstants().getInactivityPenaltyQuotient())); + } } } - return deltas; + return new Gwei[][] { rewards, penalties }; } /* - def get_justification_and_finalization_deltas(state: BeaconState) -> Tuple[List[Gwei], List[Gwei]]: - epochs_since_finality = get_current_epoch(state) + 1 - state.finalized_epoch - if epochs_since_finality <= 4: - return compute_normal_justification_and_finalization_deltas(state) - else: - return compute_inactivity_leak_deltas(state) - */ - default Gwei[][] get_justification_and_finalization_deltas(BeaconState state) { - EpochNumber epochs_since_finality = - get_current_epoch(state).increment().minus(state.getFinalizedEpoch()); - if (epochs_since_finality.lessEqual(EpochNumber.of(4))) { - return compute_normal_justification_and_finalization_deltas(state); - } else { - return compute_inactivity_leak_deltas(state); - } - } - - /* - # deltas[0] for rewards - # deltas[1] for penalties - */ + def get_crosslink_deltas(state: BeaconState) -> Tuple[List[Gwei], List[Gwei]]: + rewards = [0 for index in range(len(state.validator_registry))] + penalties = [0 for index in range(len(state.validator_registry))] + epoch = get_previous_epoch(state) + for offset in range(get_epoch_committee_count(state, epoch)): + shard = (get_epoch_start_shard(state, epoch) + offset) % SHARD_COUNT + crosslink_committee = get_crosslink_committee(state, epoch, shard) + winning_crosslink, attesting_indices = get_winning_crosslink_and_attesting_indices(state, epoch, shard) + attesting_balance = get_total_balance(state, attesting_indices) + committee_balance = get_total_balance(state, crosslink_committee) + for index in crosslink_committee: + base_reward = get_base_reward(state, index) + if index in attesting_indices: + rewards[index] += base_reward * attesting_balance // committee_balance + else: + penalties[index] += base_reward + return rewards, penalties + */ default Gwei[][] get_crosslink_deltas(BeaconState state) { - /* - deltas = [ - [0 for index in range(len(state.validator_registry))], - [0 for index in range(len(state.validator_registry))] - ] */ - Gwei[][] deltas = { - new Gwei[state.getValidatorRegistry().size().getIntValue()], - new Gwei[state.getValidatorRegistry().size().getIntValue()] - }; - Arrays.fill(deltas[0], Gwei.ZERO); - Arrays.fill(deltas[1], Gwei.ZERO); - - SlotNumber previous_epoch_start_slot = get_epoch_start_slot(get_previous_epoch(state)); - SlotNumber current_epoch_start_slot = get_epoch_start_slot(get_current_epoch(state)); - - /* for slot in range(previous_epoch_start_slot, current_epoch_start_slot): - for crosslink_committee, shard in get_crosslink_committees_at_slot(state, slot): */ - for (SlotNumber slot : previous_epoch_start_slot.iterateTo(current_epoch_start_slot)) { - List committees_and_shards = get_crosslink_committees_at_slot(state, slot); - for (ShardCommittee committee_and_shard : committees_and_shards) { - List crosslink_committee = committee_and_shard.getCommittee(); - ShardNumber shard = committee_and_shard.getShard(); - /* winning_root, participants = get_winning_root_and_participants(state, shard) - participating_balance = get_total_balance(state, participants) - total_balance = get_total_balance(state, crosslink_committee) */ - Pair> winning_root_and_participants = - get_winning_root_and_participants(state, slot, shard); - Gwei participating_balance = get_total_balance(state, winning_root_and_participants.getValue1()); - Gwei total_balance = get_total_balance(state, crosslink_committee); - - /* for index in crosslink_committee: - if index in participants: - deltas[0][index] += get_base_reward(state, index) * participating_balance // total_balance - else: - deltas[1][index] += get_base_reward(state, index) */ - for (ValidatorIndex index : crosslink_committee) { - if (winning_root_and_participants.getValue1().contains(index)) { - deltas[0][index.getIntValue()] = deltas[0][index.getIntValue()].plus( - get_base_reward(state, index).mulDiv(participating_balance, total_balance)); - } else { - deltas[1][index.getIntValue()] = deltas[1][index.getIntValue()].plus( - get_base_reward(state, index)); - } + Gwei[] rewards = new Gwei[state.getValidatorRegistry().size().getIntValue()]; + Gwei[] penalties = new Gwei[state.getValidatorRegistry().size().getIntValue()]; + Arrays.fill(rewards, Gwei.ZERO); + Arrays.fill(penalties, Gwei.ZERO); + + EpochNumber epoch = get_previous_epoch(state); + for (UInt64 offset : UInt64s.iterate(UInt64.ZERO, get_epoch_committee_count(state, epoch))) { + ShardNumber shard = get_epoch_start_shard(state, epoch) + .plusModulo(offset, getConstants().getShardCount()); + List crosslink_committee = get_crosslink_committee(state, epoch, shard); + Pair> winner = + get_winning_crosslink_and_attesting_indices(state, epoch, shard); + List attesting_indices = winner.getValue1(); + Gwei attesting_balance = get_total_balance(state, attesting_indices); + Gwei committee_balance = get_total_balance(state, crosslink_committee); + for (ValidatorIndex index : crosslink_committee) { + Gwei base_reward = get_base_reward(state, index); + if (attesting_indices.contains(index)) { + rewards[index.getIntValue()] = rewards[index.getIntValue()] + .plus(base_reward.times(attesting_balance).dividedBy(committee_balance)); + } else { + penalties[index.getIntValue()] = penalties[index.getIntValue()] + .plus(base_reward); } } } - return deltas; + return new Gwei[][] { rewards, penalties }; } /* - Note: this function mutates beacon state. + def process_rewards_and_penalties(state: BeaconState) -> None: + if get_current_epoch(state) == GENESIS_EPOCH: + return - def apply_rewards(state: BeaconState) -> None: - deltas1 = get_justification_and_finalization_deltas(state) - deltas2 = get_crosslink_deltas(state) + rewards1, penalties1 = get_attestation_deltas(state) + rewards2, penalties2 = get_crosslink_deltas(state) for i in range(len(state.validator_registry)): - state.validator_balances[i] = max( - 0, - state.validator_balances[i] + deltas1[0][i] + deltas2[0][i] - deltas1[1][i] - deltas2[1][i] - ) + increase_balance(state, i, rewards1[i] + rewards2[i]) + decrease_balance(state, i, penalties1[i] + penalties2[i]) */ - default void apply_rewards(MutableBeaconState state) { - Gwei[][] deltas1 = get_justification_and_finalization_deltas(state); - Gwei[][] deltas2 = get_crosslink_deltas(state); - for (ValidatorIndex index : state.getValidatorRegistry().size()) { - int i = index.getIntValue(); - state.getValidatorBalances().update(index, balance -> - balance.plus(deltas1[0][i]).plus(deltas2[0][i]) - .minusSat(deltas1[1][i]).minusSat(deltas2[1][i])); + default void process_rewards_and_penalties(MutableBeaconState state) { + if (get_current_epoch(state).equals(getConstants().getGenesisEpoch())) { + return; } - } - /* - def process_ejections(state: BeaconState) -> None: - """ - Iterate through the validator registry - and eject active validators with balance below ``EJECTION_BALANCE``. - """ - for index in get_active_validator_indices(state.validator_registry, get_current_epoch(state)): - if state.validator_balances[index] < EJECTION_BALANCE: - exit_validator(state, index) - */ - default List process_ejections(MutableBeaconState state) { - List ejected = new ArrayList<>(); - List active_validator_indices = - get_active_validator_indices(state.getValidatorRegistry(), get_current_epoch(state)); - for (ValidatorIndex index : active_validator_indices) { - if (state.getValidatorBalances().get(index).less(getConstants().getEjectionBalance())) { - exit_validator(state, index); - ejected.add(index); - } - } - return ejected; - } - - /* - def should_update_validator_registry(state: BeaconState) -> bool: - # Must have finalized a new block - if state.finalized_epoch <= state.validator_registry_update_epoch: - return False - # Must have processed new crosslinks on all shards of the current epoch - shards_to_check = [ - (state.current_shuffling_start_shard + i) % SHARD_COUNT - for i in range(get_current_epoch_committee_count(state)) - ] - for shard in shards_to_check: - if state.latest_crosslinks[shard].epoch <= state.validator_registry_update_epoch: - return False - return True - */ - default boolean should_update_validator_registry(BeaconState state) { - // Must have finalized a new block - if (state.getFinalizedEpoch().lessEqual(state.getValidatorRegistryUpdateEpoch())) { - return false; - } - // Must have processed new crosslinks on all shards of the current epoch - List shards_to_check = IntStream.range(0, get_current_epoch_committee_count(state)) - .mapToObj(i -> ShardNumber.of(state.getCurrentShufflingStartShard() - .plus(i).modulo(getConstants().getShardCount()))).collect(toList()); - for (ShardNumber shard : shards_to_check) { - if (state.getCurrentCrosslinks().get(shard).getEpoch() - .lessEqual(state.getValidatorRegistryUpdateEpoch())) { - return false; - } + Gwei[][] deltas1 = get_attestation_deltas(state); + Gwei[] rewards1 = deltas1[0], penalties1 = deltas1[1]; + Gwei[][] deltas2 = get_crosslink_deltas(state); + Gwei[] rewards2 = deltas2[0], penalties2 = deltas2[1]; + for (ValidatorIndex i : state.getValidatorRegistry().size()) { + increase_balance(state, i, rewards1[i.getIntValue()].plus(rewards2[i.getIntValue()])); + decrease_balance(state, i, penalties1[i.getIntValue()].plus(penalties2[i.getIntValue()])); } - - return true; } /* - """ - Update validator registry. - Note that this function mutates ``state``. - """ + def process_registry_updates(state: BeaconState) -> None: */ - default void update_validator_registry(MutableBeaconState state) { - EpochNumber current_epoch = get_current_epoch(state); - // The active validators - List active_validator_indices = - get_active_validator_indices(state.getValidatorRegistry(), current_epoch); - // The total effective balance of active validators - Gwei total_balance = get_total_balance(state, active_validator_indices); - - // The maximum balance churn in Gwei (for deposits and exits separately) - Gwei max_balance_churn = UInt64s.max( - getConstants().getMaxDepositAmount(), - total_balance.dividedBy(getConstants().getMaxBalanceChurnQuotient().times(2)) - ); - - // Activate validators within the allowable balance churn - - /* balance_churn = 0 - for index, validator in enumerate(state.validator_registry): - if validator.activation_epoch == FAR_FUTURE_EPOCH and state.validator_balances[index] >= MAX_DEPOSIT_AMOUNT: - # Check the balance churn would be within the allowance - balance_churn += get_effective_balance(state, index) - if balance_churn > max_balance_churn: - break - - # Activate validator - activate_validator(state, index, is_genesis=False) */ - Gwei balance_churn = Gwei.ZERO; + default List process_registry_updates(MutableBeaconState state) { + /* Process activation eligibility and ejections + for index, validator in enumerate(state.validator_registry): + if validator.activation_eligibility_epoch == FAR_FUTURE_EPOCH and validator.effective_balance >= MAX_EFFECTIVE_BALANCE: + validator.activation_eligibility_epoch = get_current_epoch(state) + + if is_active_validator(validator, get_current_epoch(state)) and validator.effective_balance <= EJECTION_BALANCE: + initiate_validator_exit(state, index) */ + List ejected = new ArrayList<>(); for (ValidatorIndex index : state.getValidatorRegistry().size()) { ValidatorRecord validator = state.getValidatorRegistry().get(index); - if (validator.getActivationEpoch().equals(getConstants().getFarFutureEpoch()) && - state.getValidatorBalances().get(index).greaterEqual(getConstants().getMaxDepositAmount())) { - - // Check the balance churn would be within the allowance - balance_churn = balance_churn.plus(get_effective_balance(state, index)); - if (balance_churn.greater(max_balance_churn)) { - break; - } + if (validator.getActivationEligibilityEpoch().equals(getConstants().getFarFutureEpoch()) + && validator.getEffectiveBalance().greaterEqual(getConstants().getMaxEffectiveBalance())) { + state.getValidatorRegistry().update(index, + v -> ValidatorRecord.Builder.fromRecord(v) + .withActivationEligibilityEpoch(get_current_epoch(state)).build()); + } - // Activate validator - activate_validator(state, index, false); + if (is_active_validator(validator, get_current_epoch(state)) + && validator.getEffectiveBalance().lessEqual(getConstants().getEjectionBalance())) { + initiate_validator_exit(state, index); + ejected.add(index); } } - // Exit validators within the allowable balance churn - - /* balance_churn = 0 - for index, validator in enumerate(state.validator_registry): - if validator.exit_epoch == FAR_FUTURE_EPOCH and validator.initiated_exit: - # Check the balance churn would be within the allowance - balance_churn += get_effective_balance(state, index) - if balance_churn > max_balance_churn: - break - - # Exit validator - exit_validator(state, index) */ - balance_churn = Gwei.ZERO; + /* Queue validators eligible for activation and not dequeued for activation prior to finalized epoch + activation_queue = sorted([ + index for index, validator in enumerate(state.validator_registry) if + validator.activation_eligibility_epoch != FAR_FUTURE_EPOCH and + validator.activation_epoch >= get_delayed_activation_exit_epoch(state.finalized_epoch) + ], key=lambda index: state.validator_registry[index].activation_eligibility_epoch) */ + List> activation_queue = new ArrayList<>(); for (ValidatorIndex index : state.getValidatorRegistry().size()) { - ValidatorRecord validator = state.getValidatorRegistry().get(index); - if (validator.getExitEpoch().equals(getConstants().getFarFutureEpoch()) && - validator.getInitiatedExit()) { - // Check the balance churn would be within the allowance - balance_churn = balance_churn.plus(get_effective_balance(state, index)); - if (balance_churn.greater(max_balance_churn)) { - break; - } - - // Exit validator - exit_validator(state, index); + ValidatorRecord v = state.getValidatorRegistry().get(index); + if (!v.getActivationEligibilityEpoch().equals(getConstants().getFarFutureEpoch()) + && v.getActivationEpoch().greaterEqual(get_delayed_activation_exit_epoch(state.getFinalizedEpoch()))) { + activation_queue.add(Pair.with(index, v)); } } - - state.setValidatorRegistryUpdateEpoch(current_epoch); - } - - default void update_registry_and_shuffling_data(MutableBeaconState state) { - // First set previous shuffling data to current shuffling data - state.setPreviousShufflingEpoch(state.getCurrentShufflingEpoch()); - state.setPreviousShufflingStartShard(state.getCurrentShufflingStartShard()); - state.setPreviousShufflingSeed(state.getCurrentShufflingSeed()); - EpochNumber current_epoch = get_current_epoch(state); - EpochNumber next_epoch = current_epoch.increment(); - - // Check if we should update, and if so, update - if (should_update_validator_registry(state)) { - /* update_validator_registry(state) - # If we update the registry, update the shuffling data and shards as well - state.current_shuffling_epoch = next_epoch - state.current_shuffling_start_shard = ( - state.current_shuffling_start_shard + - get_current_epoch_committee_count(state) - ) % SHARD_COUNT - state.current_shuffling_seed = generate_seed(state, state.current_shuffling_epoch) */ - update_validator_registry(state); - // If we update the registry, update the shuffling data and shards as well - state.setCurrentShufflingEpoch(next_epoch); - state.setCurrentShufflingStartShard(state.getCurrentShufflingStartShard().plusModulo( - get_current_epoch_committee_count(state), getConstants().getShardCount())); - state.setCurrentShufflingSeed(generate_seed(state, state.getCurrentShufflingEpoch())); - } else { - // If processing at least one crosslink keeps failing, then reshuffle every power of two, - // but don't update the current_shuffling_start_shard - - /* epochs_since_last_registry_update = current_epoch - state.validator_registry_update_epoch - if epochs_since_last_registry_update > 1 and is_power_of_two(epochs_since_last_registry_update): - state.current_shuffling_epoch = next_epoch - state.current_shuffling_seed = generate_seed(state, state.current_shuffling_epoch) */ - EpochNumber epochs_since_last_registry_update = current_epoch.minus( - state.getValidatorRegistryUpdateEpoch()); - if (epochs_since_last_registry_update.greater(EpochNumber.of(1)) && - is_power_of_two(epochs_since_last_registry_update)) { - state.setCurrentShufflingEpoch(next_epoch); - state.setCurrentShufflingSeed(generate_seed(state, state.getCurrentShufflingEpoch())); + activation_queue.sort(Comparator.comparing(p -> p.getValue1().getActivationEligibilityEpoch())); + int limit = get_churn_limit(state).getIntValue(); + List> limited_activation_queue = + activation_queue.size() > limit ? activation_queue.subList(0, limit) : activation_queue; + + /* Dequeued validators for activation up to churn limit (without resetting activation epoch) + for index in activation_queue[:get_churn_limit(state)]: + if validator.activation_epoch == FAR_FUTURE_EPOCH: + validator.activation_epoch = get_delayed_activation_exit_epoch(get_current_epoch(state)) */ + for (Pair p : limited_activation_queue) { + if (p.getValue1().getActivationEpoch().equals(getConstants().getFarFutureEpoch())) { + state.getValidatorRegistry().update(p.getValue0(), + v -> ValidatorRecord.Builder.fromRecord(v) + .withActivationEpoch(get_delayed_activation_exit_epoch(get_current_epoch(state))) + .build()); } } + + return ejected; } /* - """ - Process the slashings. - Note that this function mutates ``state``. - """ + def process_slashings(state: BeaconState) -> None: */ default void process_slashings(MutableBeaconState state) { + /* current_epoch = get_current_epoch(state) + active_validator_indices = get_active_validator_indices(state, current_epoch) + total_balance = get_total_balance(state, active_validator_indices) */ EpochNumber current_epoch = get_current_epoch(state); - List active_validator_indices = - get_active_validator_indices(state.getValidatorRegistry(), current_epoch); + List active_validator_indices = get_active_validator_indices(state, current_epoch); Gwei total_balance = get_total_balance(state, active_validator_indices); - // Compute `total_penalties` - Gwei total_at_start = state.getLatestSlashedBalances().get(current_epoch.increment() - .modulo(getConstants().getLatestSlashedExitLength())); - Gwei total_at_end = state.getLatestSlashedBalances() - .get(current_epoch.modulo(getConstants().getLatestSlashedExitLength())); - Gwei total_penalties = total_at_end.minusSat(total_at_start); + /* Compute `total_penalties` + total_at_start = state.latest_slashed_balances[(current_epoch + 1) % LATEST_SLASHED_EXIT_LENGTH] + total_at_end = state.latest_slashed_balances[current_epoch % LATEST_SLASHED_EXIT_LENGTH] + total_penalties = total_at_end - total_at_start */ + Gwei total_at_start = state.getLatestSlashedBalances().get( + current_epoch.increment().modulo(getConstants().getLatestSlashedExitLength())); + Gwei total_at_end = state.getLatestSlashedBalances().get( + current_epoch.modulo(getConstants().getLatestSlashedExitLength())); + Gwei total_penalties = total_at_end.minus(total_at_start); /* for index, validator in enumerate(state.validator_registry): if validator.slashed and current_epoch == validator.withdrawable_epoch - LATEST_SLASHED_EXIT_LENGTH // 2: penalty = max( - get_effective_balance(state, index) * min(total_penalties * 3, total_balance) // total_balance, - get_effective_balance(state, index) // MIN_PENALTY_QUOTIENT + validator.effective_balance * min(total_penalties * 3, total_balance) // total_balance, + validator.effective_balance // MIN_SLASHING_PENALTY_QUOTIENT ) - state.validator_balances[index] -= penalty */ - + decrease_balance(state, index, penalty) */ for (ValidatorIndex index : state.getValidatorRegistry().size()) { ValidatorRecord validator = state.getValidatorRegistry().get(index); - if (validator.getSlashed() && - current_epoch.equals(validator.getWithdrawableEpoch() - .minus(getConstants().getLatestSlashedExitLength().half()))) { - Gwei effective_balance = get_effective_balance(state, index); + if (validator.getSlashed() + && current_epoch.equals( + validator.getWithdrawableEpoch().minus(getConstants().getLatestSlashedExitLength().half()))) { + Gwei total_penalty_multiplier = UInt64s.min(total_penalties.times(3), total_balance); Gwei penalty = UInt64s.max( - effective_balance.times(UInt64s.min(total_penalties.times(3), total_balance).dividedBy(total_balance)), - effective_balance.dividedBy(getConstants().getMinPenaltyQuotient()) + validator.getEffectiveBalance().times(total_penalty_multiplier).dividedBy(total_balance), + validator.getEffectiveBalance().dividedBy(getConstants().getMinSlashingPenaltyQuotient()) ); - state.getValidatorBalances().update(index, balance -> balance.minusSat(penalty)); + decrease_balance(state, index, penalty); } } } /* - def eligible(index): - validator = state.validator_registry[index] - # Filter out dequeued validators - if validator.withdrawable_epoch != FAR_FUTURE_EPOCH: - return False - # Dequeue if the minimum amount of time has passed - else: - return get_current_epoch(state) >= validator.exit_epoch + MIN_VALIDATOR_WITHDRAWABILITY_DELAY + def process_final_updates(state: BeaconState) -> None: */ - default boolean eligible(BeaconState state, ValidatorIndex index) { - ValidatorRecord validator = state.getValidatorRegistry().get(index); - // Filter out dequeued validators - if (!validator.getWithdrawableEpoch().equals(getConstants().getFarFutureEpoch())) { - return false; - } else if (validator.getExitEpoch().equals(getConstants().getFarFutureEpoch())) { - return false; - } else { - // Dequeue if the minimum amount of time has passed - return get_current_epoch(state).greaterEqual( - validator.getExitEpoch().plus(getConstants().getMinValidatorWithdrawabilityDelay())); + default void process_final_updates(MutableBeaconState state) { + /* current_epoch = get_current_epoch(state) + next_epoch = current_epoch + 1 */ + EpochNumber current_epoch = get_current_epoch(state); + EpochNumber next_epoch = current_epoch.increment(); + + /* Reset eth1 data votes + if (state.slot + 1) % SLOTS_PER_ETH1_VOTING_PERIOD == 0: + state.eth1_data_votes = [] */ + if (state.getSlot().increment().modulo(getConstants().getSlotsPerEth1VotingPeriod()) + .equals(SlotNumber.ZERO)) { + state.getEth1DataVotes().clear(); } - } - /* - """ - Process the exit queue. - Note that this function mutates ``state``. - """ - */ - default void process_exit_queue(MutableBeaconState state) { - // eligible_indices = filter(eligible, list(range(len(state.validator_registry)))) - // Sort in order of exit epoch, - // and validators that exit within the same epoch exit in order of validator index - List sorted_eligible_indices = - StreamSupport.stream(state.getValidatorRegistry().size().spliterator(), false) - .filter(index -> eligible(state, index)) - .sorted(Comparator.comparing(index -> state.getValidatorRegistry().get(index).getExitEpoch())) - .collect(toList()); - - /* for dequeues, index in enumerate(sorted_indices): - if dequeues >= MAX_EXIT_DEQUEUES_PER_EPOCH: - break - prepare_validator_for_withdrawal(state, index) */ - for (int i = 0; i < sorted_eligible_indices.size(); i++) { - int dequeues = i; - if (dequeues >= getConstants().getMaxExitDequesPerEpoch().getIntValue()) { - break; + /* Update effective balances with hysteresis + for index, validator in enumerate(state.validator_registry): + balance = state.balances[index] + HALF_INCREMENT = EFFECTIVE_BALANCE_INCREMENT // 2 + if balance < validator.effective_balance or validator.effective_balance + 3 * HALF_INCREMENT < balance: + validator.effective_balance = min(balance - balance % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE) */ + Gwei half_increment = getConstants().getEffectiveBalanceIncrement().dividedBy(2); + for (ValidatorIndex index : state.getValidatorRegistry().size()) { + ValidatorRecord validator = state.getValidatorRegistry().get(index); + Gwei balance = state.getBalances().get(index); + if (balance.less(validator.getEffectiveBalance()) + || validator.getEffectiveBalance().plus(half_increment.times(3)).less(balance)) { + state.getValidatorRegistry().update(index, + v -> ValidatorRecord.Builder.fromRecord(v) + .withEffectiveBalance( + UInt64s.min( + balance.minus(Gwei.castFrom(balance.modulo(getConstants().getEffectiveBalanceIncrement()))), + getConstants().getMaxEffectiveBalance())) + .build()); } - prepare_validator_for_withdrawal(state, sorted_eligible_indices.get(i)); } - } - - default void finish_epoch_update(MutableBeaconState state) { - EpochNumber current_epoch = get_current_epoch(state); - EpochNumber next_epoch = current_epoch.increment(); - - // Set active index root - EpochNumber index_root_position = next_epoch - .plus(getConstants().getActivationExitDelay()).modulo(getConstants().getLatestActiveIndexRootsLength()); - state.getLatestActiveIndexRoots().set(index_root_position, hash_tree_root( - get_active_validator_indices(state.getValidatorRegistry(), - next_epoch.plus(getConstants().getActivationExitDelay())))); - // Set total slashed balances + /* Update start shard + state.latest_start_shard = (state.latest_start_shard + get_shard_delta(state, current_epoch)) % SHARD_COUNT */ + state.setLatestStartShard(state.getLatestStartShard() + .plusModulo(get_shard_delta(state, current_epoch), getConstants().getShardCount())); + + /* Set active index root + index_root_position = (next_epoch + ACTIVATION_EXIT_DELAY) % LATEST_ACTIVE_INDEX_ROOTS_LENGTH + state.latest_active_index_roots[index_root_position] = hash_tree_root( + get_active_validator_indices(state, next_epoch + ACTIVATION_EXIT_DELAY) + ) */ + EpochNumber index_root_position = next_epoch.plusModulo(getConstants().getActivationExitDelay(), + getConstants().getLatestActiveIndexRootsLength()); + state.getLatestActiveIndexRoots().set(index_root_position, + hash_tree_root( + get_active_validator_indices(state, next_epoch.plus(getConstants().getActivationExitDelay())))); + + /* Set total slashed balances + state.latest_slashed_balances[next_epoch % LATEST_SLASHED_EXIT_LENGTH] = ( + state.latest_slashed_balances[current_epoch % LATEST_SLASHED_EXIT_LENGTH] + ) */ state.getLatestSlashedBalances().set(next_epoch.modulo(getConstants().getLatestSlashedExitLength()), - state.getLatestSlashedBalances().get( - current_epoch.modulo(getConstants().getLatestSlashedExitLength()))); + state.getLatestSlashedBalances().get(current_epoch.modulo(getConstants().getLatestSlashedExitLength()))); - // Set randao mix + /* Set randao mix + state.latest_randao_mixes[next_epoch % LATEST_RANDAO_MIXES_LENGTH] = get_randao_mix(state, current_epoch) */ state.getLatestRandaoMixes().set(next_epoch.modulo(getConstants().getLatestRandaoMixesLength()), get_randao_mix(state, current_epoch)); - // Set historical root accumulator + /* Set historical root accumulator + if next_epoch % (SLOTS_PER_HISTORICAL_ROOT // SLOTS_PER_EPOCH) == 0: + historical_batch = HistoricalBatch( + block_roots=state.latest_block_roots, + state_roots=state.latest_state_roots, + ) + state.historical_roots.append(hash_tree_root(historical_batch)) */ if (next_epoch.modulo(getConstants().getSlotsPerHistoricalRoot().dividedBy(getConstants().getSlotsPerEpoch())) .equals(EpochNumber.ZERO)) { HistoricalBatch historical_batch = - new HistoricalBatch( - state.getLatestBlockRoots().listCopy(), - state.getLatestStateRoots().listCopy()); + new HistoricalBatch(state.getLatestBlockRoots().vectorCopy(), state.getLatestStateRoots().vectorCopy()); state.getHistoricalRoots().add(hash_tree_root(historical_batch)); } - // Rotate current/previous epoch attestations + /* Rotate current/previous epoch attestations + state.previous_epoch_attestations = state.current_epoch_attestations + state.current_epoch_attestations = [] */ state.getPreviousEpochAttestations().clear(); state.getPreviousEpochAttestations().addAll(state.getCurrentEpochAttestations().listCopy()); state.getCurrentEpochAttestations().clear(); diff --git a/consensus/src/main/java/org/ethereum/beacon/consensus/spec/ForkChoice.java b/consensus/src/main/java/org/ethereum/beacon/consensus/spec/ForkChoice.java index 8910fd6f6..f7b47f5bc 100644 --- a/consensus/src/main/java/org/ethereum/beacon/consensus/spec/ForkChoice.java +++ b/consensus/src/main/java/org/ethereum/beacon/consensus/spec/ForkChoice.java @@ -14,14 +14,13 @@ import org.ethereum.beacon.core.types.ValidatorIndex; import org.javatuples.Pair; import tech.pegasys.artemis.ethereum.core.Hash32; -import tech.pegasys.artemis.util.collections.ReadList; import tech.pegasys.artemis.util.uint.UInt64; /** * Fork choice rule. * * @see Beacon + * href="https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#beacon-chain-fork-choice-rule">Beacon * chain fork choice rule in the spec. */ public interface ForkChoice extends HelperFunction { @@ -62,13 +61,12 @@ default BeaconBlock lmd_ghost( Function> getBlock, Function> getChildrenBlocks, Function> get_latest_attestation) { - ReadList validators = state.getValidatorRegistry(); List active_validator_indices = - get_active_validator_indices(validators, get_current_epoch(state)); + get_active_validator_indices(state, get_current_epoch(state)); List> active_validators = new ArrayList<>(); for (ValidatorIndex index : active_validator_indices) { - active_validators.add(Pair.with(index, validators.get(index))); + active_validators.add(Pair.with(index, state.getValidatorRegistry().get(index))); } List> attestation_targets = new ArrayList<>(); @@ -79,7 +77,7 @@ default BeaconBlock lmd_ghost( BeaconBlock head = startBlock; while (true) { - List children = getChildrenBlocks.apply(signed_root(head)); + List children = getChildrenBlocks.apply(signing_root(head)); if (children.isEmpty()) { return head; } else { @@ -112,7 +110,7 @@ default Optional get_latest_attestation_target( /* def get_vote_count(block: BeaconBlock) -> int: return sum( - get_effective_balance(start_state.validator_balances[validator_index]) // FORK_CHOICE_BALANCE_INCREMENT + get_effective_balance(start_state.validator_balances[validator_index]) // EFFECTIVE_BALANCE_INCREMENT for validator_index, target in attestation_targets if get_ancestor(store, target, block.slot) == block ) @@ -126,7 +124,7 @@ default UInt64 get_vote_count( return attestation_targets.stream().filter( target -> get_ancestor(target.getValue1(), block.getSlot(), getBlock) .filter(ancestor -> ancestor.equals(block)).isPresent()) - .map(target -> get_effective_balance(startState, target.getValue0()).dividedBy(getConstants().getForkChoiceBalanceIncrement())) + .map(target -> get_effective_balance(startState, target.getValue0()).dividedBy(getConstants().getEffectiveBalanceIncrement())) .reduce(Gwei.ZERO, Gwei::plus); } diff --git a/consensus/src/main/java/org/ethereum/beacon/consensus/spec/HelperFunction.java b/consensus/src/main/java/org/ethereum/beacon/consensus/spec/HelperFunction.java index 6a4ed1f65..e135904f3 100644 --- a/consensus/src/main/java/org/ethereum/beacon/consensus/spec/HelperFunction.java +++ b/consensus/src/main/java/org/ethereum/beacon/consensus/spec/HelperFunction.java @@ -4,26 +4,22 @@ import static java.util.stream.Collectors.toList; import static org.ethereum.beacon.core.spec.SignatureDomains.ATTESTATION; +import com.google.common.collect.Ordering; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; -import java.util.Optional; import java.util.stream.Collectors; -import java.util.stream.IntStream; -import org.ethereum.beacon.consensus.BeaconChainSpec; +import java.util.stream.Stream; import org.ethereum.beacon.core.BeaconBlock; import org.ethereum.beacon.core.BeaconBlockHeader; import org.ethereum.beacon.core.BeaconState; import org.ethereum.beacon.core.MutableBeaconState; -import org.ethereum.beacon.core.operations.Deposit; +import org.ethereum.beacon.core.operations.Attestation; import org.ethereum.beacon.core.operations.attestation.AttestationData; import org.ethereum.beacon.core.operations.attestation.AttestationDataAndCustodyBit; -import org.ethereum.beacon.core.operations.deposit.DepositInput; -import org.ethereum.beacon.core.operations.slashing.SlashableAttestation; -import org.ethereum.beacon.core.spec.SignatureDomains; -import org.ethereum.beacon.core.state.Fork; +import org.ethereum.beacon.core.operations.slashing.IndexedAttestation; import org.ethereum.beacon.core.state.ShardCommittee; import org.ethereum.beacon.core.state.ValidatorRecord; import org.ethereum.beacon.core.types.BLSPubkey; @@ -40,7 +36,6 @@ import org.ethereum.beacon.crypto.MessageParameters; import tech.pegasys.artemis.ethereum.core.Hash32; import tech.pegasys.artemis.util.bytes.Bytes32; -import tech.pegasys.artemis.util.bytes.Bytes32s; import tech.pegasys.artemis.util.bytes.Bytes4; import tech.pegasys.artemis.util.bytes.Bytes8; import tech.pegasys.artemis.util.bytes.BytesValue; @@ -53,7 +48,7 @@ * Helper functions. * * @see Helper + * href="https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#helper-functions">Helper * functions in ths spec. */ public interface HelperFunction extends SpecCommons { @@ -62,14 +57,6 @@ default Hash32 hash(BytesValue data) { return getHashFunction().apply(data); } - /* - def xor(bytes1: Bytes32, bytes2: Bytes32) -> Bytes32: - return bytes(a ^ b for a, b in zip(bytes1, bytes2)) - */ - default Bytes32 xor(Bytes32 bytes1, Bytes32 bytes2) { - return Bytes32s.xor(bytes1, bytes2); - } - /* def get_temporary_block_header(block: BeaconBlock) -> BeaconBlockHeader: """ @@ -80,8 +67,8 @@ def get_temporary_block_header(block: BeaconBlock) -> BeaconBlockHeader: previous_block_root=block.previous_block_root, state_root=ZERO_HASH, block_body_root=hash_tree_root(block.body), - # signed_root(block) is used for block id purposes so signature is a stub - signature=EMPTY_SIGNATURE, + # signing_root(block) is used for block id purposes so signature is a stub + signature=BLSSignature.ZERO, ) */ default BeaconBlockHeader get_temporary_block_header(BeaconBlock block) { @@ -90,261 +77,179 @@ default BeaconBlockHeader get_temporary_block_header(BeaconBlock block) { block.getPreviousBlockRoot(), Hash32.ZERO, hash_tree_root(block.getBody()), - getConstants().getEmptySignature()); + BLSSignature.ZERO); } /* - def get_epoch_committee_count(active_validator_count: int) -> int: - """ - Return the number of committees in one epoch. - """ - return max( - 1, - min( - SHARD_COUNT // SLOTS_PER_EPOCH, - active_validator_count // SLOTS_PER_EPOCH // TARGET_COMMITTEE_SIZE, - ) - ) * SLOTS_PER_EPOCH + def get_epoch_committee_count(state: BeaconState, epoch: Epoch) -> int: + """ + Return the number of committees at ``epoch``. + """ + active_validator_indices = get_active_validator_indices(state, epoch) + return max( + 1, + min( + SHARD_COUNT // SLOTS_PER_EPOCH, + len(active_validator_indices) // SLOTS_PER_EPOCH // TARGET_COMMITTEE_SIZE, + ) + ) * SLOTS_PER_EPOCH */ - default int get_epoch_committee_count(int active_validator_count) { - return UInt64s.max(UInt64.valueOf(1), + default UInt64 get_epoch_committee_count(BeaconState state, EpochNumber epoch) { + List active_validator_indices = get_active_validator_indices(state, epoch); + + return UInt64s.max( + UInt64.valueOf(1), UInt64s.min( getConstants().getShardCount().dividedBy(getConstants().getSlotsPerEpoch()), - UInt64.valueOf(active_validator_count) + UInt64.valueOf(active_validator_indices.size()) .dividedBy(getConstants().getSlotsPerEpoch()) .dividedBy(getConstants().getTargetCommitteeSize()) - )).times(getConstants().getSlotsPerEpoch()).intValue(); - } - - /* - def get_previous_epoch_committee_count(state: BeaconState) -> int: - """ - Return the number of committees in the previous epoch of the given ``state``. - """ - previous_active_validators = get_active_validator_indices( - state.validator_registry, - state.previous_shuffling_epoch, - ) - return get_epoch_committee_count(len(previous_active_validators)) - */ - default int get_previous_epoch_committee_count(BeaconState state) { - List previous_active_validators = get_active_validator_indices( - state.getValidatorRegistry(), - state.getPreviousShufflingEpoch()); - return get_epoch_committee_count(previous_active_validators.size()); + )).times(getConstants().getSlotsPerEpoch()); } /* - def get_current_epoch_committee_count(state: BeaconState) -> int: - """ - Return the number of committees in the current epoch of the given ``state``. - """ - current_active_validators = get_active_validator_indices( - state.validator_registry, - state.current_shuffling_epoch, - ) - return get_epoch_committee_count(len(current_active_validators)) + def get_shard_delta(state: BeaconState, epoch: Epoch) -> int: + """ + Return the number of shards to increment ``state.latest_start_shard`` during ``epoch``. + """ + return min(get_epoch_committee_count(state, epoch), SHARD_COUNT - SHARD_COUNT // SLOTS_PER_EPOCH) */ - default int get_current_epoch_committee_count(BeaconState state) { - List current_active_validators = get_active_validator_indices( - state.getValidatorRegistry(), - state.getCurrentShufflingEpoch()); - return get_epoch_committee_count(current_active_validators.size()); + default UInt64 get_shard_delta(BeaconState state, EpochNumber epoch) { + return UInt64s.min( + get_epoch_committee_count(state, epoch), + getConstants().getShardCount().minus( + getConstants().getShardCount().dividedBy(getConstants().getSlotsPerEpoch())) + ); } /* - def get_next_epoch_committee_count(state: BeaconState) -> int: - """ - Return the number of committees in the next epoch of the given ``state``. - """ - next_active_validators = get_active_validator_indices( - state.validator_registry, - get_current_epoch(state) + 1, - ) - return get_epoch_committee_count(len(next_active_validators)) + def get_epoch_start_shard(state: BeaconState, epoch: Epoch) -> Shard: + assert epoch <= get_current_epoch(state) + 1 + check_epoch = get_current_epoch(state) + 1 + shard = (state.latest_start_shard + get_shard_delta(state, get_current_epoch(state))) % SHARD_COUNT + while check_epoch > epoch: + check_epoch -= 1 + shard = (shard + SHARD_COUNT - get_shard_delta(state, check_epoch)) % SHARD_COUNT + return shard */ - default int get_next_epoch_committee_count(BeaconState state) { - List next_active_validators = get_active_validator_indices( - state.getValidatorRegistry(), - get_current_epoch(state).increment()); - return get_epoch_committee_count(next_active_validators.size()); - } + default ShardNumber get_epoch_start_shard(BeaconState state, EpochNumber epoch) { + assertTrue(epoch.lessEqual(get_current_epoch(state).increment())); + EpochNumber check_epoch = get_current_epoch(state).increment(); + ShardNumber shard = state.getLatestStartShard() + .plusModulo(get_shard_delta(state, get_current_epoch(state)), getConstants().getShardCount()); + while ((check_epoch.greater(epoch))) { + check_epoch = check_epoch.decrement(); + shard = ShardNumber.of( + shard + .plus(getConstants().getShardCount()) + .minus(get_shard_delta(state, check_epoch)) + .modulo(getConstants().getShardCount())); + } - default List get_crosslink_committees_at_slot( - BeaconState state, SlotNumber slot) { - return get_crosslink_committees_at_slot(state, slot, false); + return shard; } /* - Return the list of ``(committee, shard)`` tuples for the ``slot``. - Note: There are two possible shufflings for crosslink committees for a - ``slot`` in the next epoch -- with and without a `registry_change` + def get_attestation_slot(state: BeaconState, attestation: Attestation) -> Slot: + epoch = attestation.data.target_epoch + committee_count = get_epoch_committee_count(state, epoch) + offset = (attestation.data.shard + SHARD_COUNT - get_epoch_start_shard(state, epoch)) % SHARD_COUNT + return get_epoch_start_slot(epoch) + offset // (committee_count // SLOTS_PER_EPOCH) */ - default List get_crosslink_committees_at_slot( - BeaconState state, SlotNumber slot, boolean registry_change) { - - EpochNumber epoch = slot_to_epoch(slot); - EpochNumber currentEpoch = get_current_epoch(state); - EpochNumber previousEpoch = get_previous_epoch(state); - EpochNumber nextEpoch = currentEpoch.increment(); - - assertTrue(previousEpoch.lessEqual(epoch) && epoch.lessEqual(nextEpoch)); - - Hash32 seed; - int committees_per_epoch; - EpochNumber shuffling_epoch; - ShardNumber shuffling_start_shard; - - if (epoch.equals(currentEpoch)) { - /* - if epoch == current_epoch: - committees_per_epoch = get_current_epoch_committee_count(state) - seed = state.current_shuffling_seed - shuffling_epoch = state.current_shuffling_epoch - shuffling_start_shard = state.current_shuffling_start_shard */ - - committees_per_epoch = get_current_epoch_committee_count(state); - seed = state.getCurrentShufflingSeed(); - shuffling_epoch = state.getCurrentShufflingEpoch(); - shuffling_start_shard = state.getCurrentShufflingStartShard(); - } else if (epoch.equals(previousEpoch)) { - /* - elif epoch == previous_epoch: - committees_per_epoch = get_previous_epoch_committee_count(state) - seed = state.previous_shuffling_seed - shuffling_epoch = state.previous_shuffling_epoch - shuffling_start_shard = state.previous_shuffling_start_shard */ - committees_per_epoch = get_previous_epoch_committee_count(state); - seed = state.getPreviousShufflingSeed(); - shuffling_epoch = state.getPreviousShufflingEpoch(); - shuffling_start_shard = state.getPreviousShufflingStartShard(); - } else if (epoch.equals(nextEpoch)) { - /* - elif epoch == next_epoch: - epochs_since_last_registry_update = current_epoch - state.validator_registry_update_epoch */ - - EpochNumber epochs_since_last_registry_update = - currentEpoch.minus(state.getValidatorRegistryUpdateEpoch()); - - if (registry_change) { - /* - if registry_change: - committees_per_epoch = get_next_epoch_committee_count(state) - seed = generate_seed(state, next_epoch) - shuffling_epoch = next_epoch - current_committees_per_epoch = get_current_epoch_committee_count(state) - shuffling_start_shard = (state.current_shuffling_start_shard + current_committees_per_epoch) % SHARD_COUNT */ - - committees_per_epoch = get_next_epoch_committee_count(state); - seed = generate_seed(state, nextEpoch); - shuffling_epoch = nextEpoch; - int current_committees_per_epoch = get_current_epoch_committee_count(state); - shuffling_start_shard = ShardNumber.of(state.getCurrentShufflingStartShard() - .plus(current_committees_per_epoch).modulo(getConstants().getShardCount())); - } else if (epochs_since_last_registry_update.greater(EpochNumber.of(1)) && - is_power_of_two(epochs_since_last_registry_update)) { - /* - elif epochs_since_last_registry_update > 1 and is_power_of_two(epochs_since_last_registry_update): - committees_per_epoch = get_next_epoch_committee_count(state) - seed = generate_seed(state, next_epoch) - shuffling_epoch = next_epoch - shuffling_start_shard = state.current_shuffling_start_shard */ - - committees_per_epoch = get_next_epoch_committee_count(state); - seed = generate_seed(state, nextEpoch); - shuffling_epoch = nextEpoch; - shuffling_start_shard = state.getCurrentShufflingStartShard(); - } else { - /* - else: - committees_per_epoch = get_current_epoch_committee_count(state) - seed = state.current_shuffling_seed - shuffling_epoch = state.current_shuffling_epoch - shuffling_start_shard = state.current_shuffling_start_shard */ - - committees_per_epoch = get_current_epoch_committee_count(state); - seed = state.getCurrentShufflingSeed(); - shuffling_epoch = state.getCurrentShufflingEpoch(); - shuffling_start_shard = state.getCurrentShufflingStartShard(); - } - } else { - throw new BeaconChainSpec.SpecAssertionFailed(); - } - - /* - shuffling = get_shuffling( - seed, - state.validator_registry, - shuffling_epoch, - ) */ - List> shuffling = get_shuffling2( - seed, - state.getValidatorRegistry(), - shuffling_epoch + default SlotNumber get_attestation_slot(BeaconState state, AttestationData data) { + EpochNumber epoch = data.getTargetEpoch(); + UInt64 committee_count = get_epoch_committee_count(state, epoch); + ShardNumber offset = ShardNumber.of( + data.getShard() + .plus(getConstants().getShardCount()) + .minus(get_epoch_start_shard(state, epoch)) + .modulo(getConstants().getShardCount()) ); + return get_epoch_start_slot(epoch) + .plus(offset.dividedBy(committee_count.dividedBy(getConstants().getSlotsPerEpoch()))); + } - /* - offset = slot % SLOTS_PER_EPOCH - committees_per_slot = committees_per_epoch // SLOTS_PER_EPOCH - slot_start_shard = (shuffling_start_shard + committees_per_slot * offset) % SHARD_COUNT */ - SlotNumber offset = slot.modulo(getConstants().getSlotsPerEpoch()); - UInt64 committees_per_slot = UInt64.valueOf(committees_per_epoch).dividedBy( - getConstants().getSlotsPerEpoch()); - ShardNumber slot_start_shard = ShardNumber.of( - shuffling_start_shard.plus(committees_per_slot).times(offset).modulo( - getConstants().getShardCount())); - - /* - return [ - ( - shuffling[committees_per_slot * offset + i], - (slot_start_shard + i) % SHARD_COUNT, - ) - for i in range(committees_per_slot) - ] */ + /** + * This method has been superseded by {@link #get_crosslink_committee(BeaconState, EpochNumber, ShardNumber)}. + * However, it's still convenient for various log outputs, thus, it's been rewritten with usage + * of its replacement. + */ + default List get_crosslink_committees_at_slot(BeaconState state, SlotNumber slot) { List ret = new ArrayList<>(); - for(int i = 0; i < committees_per_slot.intValue(); i++) { - ShardCommittee committee = new ShardCommittee( - shuffling.get(committees_per_slot.times(offset).plus(i).getIntValue()), - slot_start_shard.plusModulo(i, getConstants().getShardCount())); - ret.add(committee); + EpochNumber epoch = slot_to_epoch(slot); + UInt64 committeesPerSlot = get_epoch_committee_count(state, epoch) + .dividedBy(getConstants().getSlotsPerEpoch()); + SlotNumber slotOffset = slot.modulo(getConstants().getSlotsPerEpoch()); + for (UInt64 offset : UInt64s.iterate(committeesPerSlot.times(slotOffset), + committeesPerSlot.times(slotOffset.increment()))) { + ShardNumber shard = get_epoch_start_shard(state, epoch) + .plusModulo(offset, getConstants().getShardCount()); + List committee = get_crosslink_committee(state, epoch, shard); + ret.add(new ShardCommittee(committee, shard)); } return ret; } /* - def get_beacon_proposer_index(state: BeaconState, - slot: Slot, - registry_change: bool=False) -> ValidatorIndex: + def get_beacon_proposer_index(state: BeaconState) -> ValidatorIndex: """ - Return the beacon proposer index for the ``slot``. + Return the current beacon proposer index. """ - epoch = slot_to_epoch(slot) - current_epoch = get_current_epoch(state) - previous_epoch = get_previous_epoch(state) - next_epoch = current_epoch + 1 - - assert previous_epoch <= epoch <= next_epoch - - first_committee, _ = get_crosslink_committees_at_slot(state, slot, registry_change)[0] - return first_committee[epoch % len(first_committee)] + epoch = get_current_epoch(state) + committees_per_slot = get_epoch_committee_count(state, epoch) // SLOTS_PER_EPOCH + offset = committees_per_slot * (state.slot % SLOTS_PER_EPOCH) + shard = (get_epoch_start_shard(state, epoch) + offset) % SHARD_COUNT + first_committee = get_crosslink_committee(state, epoch, shard) + MAX_RANDOM_BYTE = 2**8 - 1 + seed = generate_seed(state, epoch) + i = 0 + while True: + candidate_index = first_committee[(epoch + i) % len(first_committee)] + random_byte = hash(seed + int_to_bytes8(i // 32))[i % 32] + effective_balance = state.validator_registry[candidate_index].effective_balance + if effective_balance * MAX_RANDOM_BYTE >= MAX_EFFECTIVE_BALANCE * random_byte: + return candidate_index + i += 1 */ - default ValidatorIndex get_beacon_proposer_index(BeaconState state, SlotNumber slot, boolean registryChange) { - EpochNumber epoch = slot_to_epoch(slot); - EpochNumber currentEpoch = get_current_epoch(state); - EpochNumber previousEpoch = get_previous_epoch(state); - EpochNumber nextEpoch = currentEpoch.increment(); - - assertTrue(previousEpoch.lessEqual(epoch) && epoch.lessEqual(nextEpoch)); - - List first_committee = - get_crosslink_committees_at_slot(state, slot, registryChange).get(0).getCommittee(); - return first_committee.get(epoch.modulo(first_committee.size()).getIntValue()); + int MAX_RANDOM_BYTE = (1 << 8) - 1; + default ValidatorIndex get_beacon_proposer_index(BeaconState state) { + EpochNumber epoch = get_current_epoch(state); + UInt64 committees_per_slot = get_epoch_committee_count(state, epoch) + .dividedBy(getConstants().getSlotsPerEpoch()); + SlotNumber offset = SlotNumber.castFrom( + committees_per_slot.times( + state.getSlot().modulo(getConstants().getSlotsPerEpoch()).getIntValue())); + ShardNumber shard = get_epoch_start_shard(state, epoch) + .plusModulo(offset, getConstants().getShardCount()); + List first_committee = get_crosslink_committee(state, epoch, shard); + Hash32 seed = generate_seed(state, epoch); + int i = 0; + while (true) { + ValidatorIndex candidate_index = first_committee.get( + epoch.plus(i).modulo(first_committee.size()).getIntValue()); + int random_byte = hash(seed.concat(int_to_bytes8(i / Bytes32.SIZE))) + .get(i % Bytes32.SIZE) & 0xFF; + Gwei effective_balance = state.getValidatorRegistry().get(candidate_index).getEffectiveBalance(); + if (effective_balance.times(MAX_RANDOM_BYTE).greaterEqual( + getConstants().getMaxEffectiveBalance().times(random_byte))) { + return candidate_index; + } + i += 1; + } } - default ValidatorIndex get_beacon_proposer_index(BeaconState state, SlotNumber slot) { - return get_beacon_proposer_index(state, slot, false); + /* + def is_slashable_validator(validator: Validator, epoch: Epoch) -> bool: + """ + Check if ``validator`` is slashable. + """ + return validator.slashed is False and (validator.activation_epoch <= epoch < validator.withdrawable_epoch) + */ + default boolean is_slashable_validator(ValidatorRecord validator, EpochNumber epoch) { + return !validator.getSlashed() + && validator.getActivationEpoch().lessEqual(epoch) + && epoch.less(validator.getWithdrawableEpoch()); } /* @@ -360,17 +265,16 @@ default boolean is_active_validator(ValidatorRecord validator, EpochNumber epoch } /* - def get_active_validator_indices(validators: List[Validator], epoch: EpochNumber) -> List[ValidatorIndex]: - """ - Get indices of active validators from ``validators``. - """ - return [i for i, v in enumerate(validators) if is_active_validator(v, epoch)] + def get_active_validator_indices(state: BeaconState, epoch: Epoch) -> List[ValidatorIndex]: + """ + Get active validator indices at ``epoch``. + """ + return [i for i, v in enumerate(state.validator_registry) if is_active_validator(v, epoch)] */ - default List get_active_validator_indices( - ReadList validators, EpochNumber epochNumber) { + default List get_active_validator_indices(BeaconState state, EpochNumber epoch) { ArrayList ret = new ArrayList<>(); - for (ValidatorIndex i : validators.size()) { - if (is_active_validator(validators.get(i), epochNumber)) { + for (ValidatorIndex i : state.getValidatorRegistry().size()) { + if (is_active_validator(state.getValidatorRegistry().get(i), epoch)) { ret.add(i); } } @@ -378,61 +282,43 @@ default List get_active_validator_indices( } /* - def get_randao_mix(state: BeaconState, - epoch: EpochNumber) -> Bytes32: - """ - Return the randao mix at a recent ``epoch``. - """ - assert get_current_epoch(state) - LATEST_RANDAO_MIXES_LENGTH < epoch <= get_current_epoch(state) - return state.latest_randao_mixes[epoch % LATEST_RANDAO_MIXES_LENGTH] - */ - default Hash32 get_randao_mix(BeaconState state, EpochNumber epoch) { - assertTrue(get_current_epoch(state).minus(getConstants().getLatestRandaoMixesLength()).less(epoch)); - assertTrue(epoch.lessEqual(get_current_epoch(state))); - return state.getLatestRandaoMixes().get( - epoch.modulo(getConstants().getLatestRandaoMixesLength())); + def increase_balance(state: BeaconState, index: ValidatorIndex, delta: Gwei) -> None: + """ + Increase validator balance by ``delta``. + """ + state.balances[index] += delta + */ + default void increase_balance(MutableBeaconState state, ValidatorIndex index, Gwei delta) { + state.getBalances().update(index, balance -> balance.plus(delta)); } /* - def get_permuted_index(index: int, list_size: int, seed: Bytes32) -> int: - """ - Return `p(index)` in a pseudorandom permutation `p` of `0...list_size-1` with ``seed`` as entropy. - - Utilizes 'swap or not' shuffling found in - https://link.springer.com/content/pdf/10.1007%2F978-3-642-32009-5_1.pdf - See the 'generalized domain' algorithm on page 3. - """ - assert index < list_size - assert list_size <= 2**40 - - for round in range(SHUFFLE_ROUND_COUNT): - pivot = bytes_to_int(hash(seed + int_to_bytes1(round))[0:8]) % list_size - flip = (pivot - index) % list_size - position = max(index, flip) - source = hash(seed + int_to_bytes1(round) + int_to_bytes4(position // 256)) - byte = source[(position % 256) // 8] - bit = (byte >> (position % 8)) % 2 - index = flip if bit else index - - return index + def decrease_balance(state: BeaconState, index: ValidatorIndex, delta: Gwei) -> None: + """ + Decrease validator balance by ``delta`` with underflow protection. + """ + state.balances[index] = 0 if delta > state.balances[index] else state.balances[index] - delta */ - default UInt64 get_permuted_index(UInt64 index, UInt64 listSize, Bytes32 seed) { - assertTrue(index.compareTo(listSize) < 0); - assertTrue(listSize.compareTo(UInt64.valueOf(1L << 40)) <= 0); - - for (int round = 0; round < getConstants().getShuffleRoundCount(); round++) { - Bytes8 pivotBytes = Bytes8.wrap(hash(seed.concat(int_to_bytes1(round))), 0); - long pivot = bytes_to_int(pivotBytes).modulo(listSize).getValue(); - UInt64 flip = UInt64.valueOf(Math.floorMod(pivot - index.getValue(), listSize.getValue())); - UInt64 position = UInt64s.max(index, flip); - Bytes4 positionBytes = int_to_bytes4(position.dividedBy(UInt64.valueOf(256))); - Bytes32 source = hash(seed.concat(int_to_bytes1(round)).concat(positionBytes)); - int byteV = source.get(position.modulo(256).getIntValue() / 8) & 0xFF; - int bit = ((byteV >> (position.modulo(8).getIntValue())) % 2) & 0xFF; - index = bit > 0 ? flip : index; + default void decrease_balance(MutableBeaconState state, ValidatorIndex index, Gwei delta) { + if (delta.greater(state.getBalances().get(index))) { + state.getBalances().update(index, balance -> Gwei.ZERO); + } else { + state.getBalances().update(index, balance -> balance.minus(delta)); } + } - return index; + /* + def get_randao_mix(state: BeaconState, + epoch: Epoch) -> Bytes32: + """ + Return the randao mix at a recent ``epoch``. + ``epoch`` expected to be between (current_epoch - LATEST_RANDAO_MIXES_LENGTH, current_epoch]. + """ + return state.latest_randao_mixes[epoch % LATEST_RANDAO_MIXES_LENGTH] + */ + default Hash32 get_randao_mix(BeaconState state, EpochNumber epoch) { + return state.getLatestRandaoMixes().get( + epoch.modulo(getConstants().getLatestRandaoMixesLength())); } /** @@ -516,6 +402,10 @@ default Bytes4 int_to_bytes4(long value) { return Bytes4.ofUnsignedIntLittleEndian(value & 0xFFFFFF); } + default Bytes8 int_to_bytes8(long value) { + return Bytes8.longToBytes8LittleEndian(value); + } + default Bytes4 int_to_bytes4(UInt64 value) { return int_to_bytes4(value.getValue()); } @@ -535,7 +425,7 @@ def split(values: List[Any], split_count: int) -> List[Any]: for i in range(split_count) ] */ - default List> split(List values, int split_count) { + default List> split(List values, int split_count) { List> ret = new ArrayList<>(); for (int i = 0; i < split_count; i++) { int fromIdx = values.size() * i / split_count; @@ -546,48 +436,90 @@ default List> split(List values, int split_count) { } /* - def get_shuffling(seed: Bytes32, - validators: List[Validator], - epoch: Epoch) -> List[List[ValidatorIndex]] - """ - Shuffle active validators and split into crosslink committees. - Return a list of committees (each a list of validator indices). - """ - # Shuffle active validator indices - active_validator_indices = get_active_validator_indices(validators, epoch) - length = len(active_validator_indices) - shuffled_indices = [active_validator_indices[get_permuted_index(i, length, seed)] for i in range(length)] + def get_shuffled_index(index: ValidatorIndex, index_count: int, seed: Bytes32) -> ValidatorIndex: + """ + Return the shuffled validator index corresponding to ``seed`` (and ``index_count``). + """ + assert index < index_count + assert index_count <= 2**40 + + # Swap or not (https://link.springer.com/content/pdf/10.1007%2F978-3-642-32009-5_1.pdf) + # See the 'generalized domain' algorithm on page 3 + for round in range(SHUFFLE_ROUND_COUNT): + pivot = bytes_to_int(hash(seed + int_to_bytes1(round))[0:8]) % index_count + flip = (pivot - index) % index_count + position = max(index, flip) + source = hash(seed + int_to_bytes1(round) + int_to_bytes4(position // 256)) + byte = source[(position % 256) // 8] + bit = (byte >> (position % 8)) % 2 + index = flip if bit else index + + return index + */ + default UInt64 get_shuffled_index(UInt64 index, UInt64 index_count, Bytes32 seed) { + assertTrue(index.compareTo(index_count) < 0); + assertTrue(index_count.compareTo(UInt64.valueOf(1L << 40)) <= 0); + + for (int round = 0; round < getConstants().getShuffleRoundCount(); round++) { + Bytes8 pivotBytes = Bytes8.wrap(hash(seed.concat(int_to_bytes1(round))), 0); + long pivot = bytes_to_int(pivotBytes).modulo(index_count).getValue(); + UInt64 flip = UInt64.valueOf(Math.floorMod(pivot - index.getValue(), index_count.getValue())); + UInt64 position = UInt64s.max(index, flip); + Bytes4 positionBytes = int_to_bytes4(position.dividedBy(UInt64.valueOf(256))); + Bytes32 source = hash(seed.concat(int_to_bytes1(round)).concat(positionBytes)); + int byteV = source.get(position.modulo(256).getIntValue() / 8) & 0xFF; + int bit = ((byteV >> (position.modulo(8).getIntValue())) % 2) & 0xFF; + index = bit > 0 ? flip : index; + } + + return index; + } - # Split the shuffled active validator indices - return split(shuffled_indices, get_epoch_committee_count(length)) + /* + def compute_committee(indices: List[ValidatorIndex], seed: Bytes32, index: int, count: int) -> List[ValidatorIndex]: + start = (len(indices) * index) // count + end = (len(indices) * (index + 1)) // count + return [indices[get_shuffled_index(i, len(indices), seed)] for i in range(start, end)] */ - default List> get_shuffling(Hash32 seed, - ReadList validators, - EpochNumber epoch) { - List active_validator_indices = get_active_validator_indices(validators, epoch); - int length = active_validator_indices.size(); - List shuffled_indices = - IntStream.range(0, length) - .mapToObj(i -> get_permuted_index(UInt64.valueOf(i), UInt64.valueOf(length), seed)) - .map(permutedIndex -> active_validator_indices.get(permutedIndex.getIntValue())) - .collect(toList()); - return split(shuffled_indices, get_epoch_committee_count(length)); + default List compute_committee(List indices, Bytes32 seed, UInt64 index, UInt64 count) { + UInt64 start = index.times(indices.size()).dividedBy(count); + UInt64 end = index.increment().times(indices.size()).dividedBy(count); + List result = new ArrayList<>(); + for (UInt64 i = start; i.compareTo(end) < 0; i = i.increment()) { + UInt64 shuffled_index = get_shuffled_index(i, UInt64.valueOf(indices.size()), seed); + result.add(indices.get(shuffled_index.getIntValue())); + } + return result; } /** - * An optimized version of {@link #get_shuffling(Hash32, ReadList, EpochNumber)}. + * An optimized version of {@link #compute_committee(List, Bytes32, UInt64, UInt64)}. * Based on {@link #get_permuted_list(List, Bytes32)}. */ - default List> get_shuffling2(Hash32 seed, - ReadList validators, - EpochNumber epoch) { - List active_validator_indices = get_active_validator_indices(validators, epoch); - int length = active_validator_indices.size(); - - List shuffled_indices = get_permuted_list(active_validator_indices, seed) + default List compute_committee2(List indices, Bytes32 seed, UInt64 index, UInt64 count) { + List shuffled_indices = get_permuted_list(indices, seed) .stream().map(ValidatorIndex::new).collect(toList()); + return split(shuffled_indices, count.getIntValue()).get(index.getIntValue()); + } - return split(shuffled_indices, get_epoch_committee_count(length)); + /* + def get_crosslink_committee(state: BeaconState, epoch: Epoch, shard: Shard) -> List[ValidatorIndex]: + return compute_committee( + indices=get_active_validator_indices(state, epoch), + seed=generate_seed(state, epoch), + index=(shard + SHARD_COUNT - get_epoch_start_shard(state, epoch)) % SHARD_COUNT, + count=get_epoch_committee_count(state, epoch), + ) + */ + default List get_crosslink_committee(BeaconState state, EpochNumber epoch, ShardNumber shard) { + return compute_committee2( + get_active_validator_indices(state, epoch), + generate_seed(state, epoch), + shard.plus(getConstants().getShardCount()) + .minus(get_epoch_start_shard(state, epoch)) + .modulo(getConstants().getShardCount()), + get_epoch_committee_count(state, epoch) + ); } /* @@ -627,19 +559,20 @@ Returns the effective balance (also known as "balance at stake") for a ``validat */ default Gwei get_effective_balance(BeaconState state, ValidatorIndex validatorIdx) { return UInt64s.min( - state.getValidatorBalances().get(validatorIdx), - getConstants().getMaxDepositAmount()); + state.getBalances().get(validatorIdx), + getConstants().getMaxEffectiveBalance()); } /* - def get_total_balance(state: BeaconState, validators: List[ValidatorIndex]) -> Gwei: + def get_total_balance(state: BeaconState, indices: List[ValidatorIndex]) -> Gwei: """ Return the combined effective balance of an array of ``validators``. """ - return sum([get_effective_balance(state, i) for i in validators]) + return sum([state.validator_registry[index].effective_balance for index in indices]) */ - default Gwei get_total_balance(BeaconState state, Collection validators) { - return validators.stream().map(index -> get_effective_balance(state, index)) + default Gwei get_total_balance(BeaconState state, Collection indices) { + return indices.stream() + .map(index -> state.getValidatorRegistry().get(index).getEffectiveBalance()) .reduce(Gwei.ZERO, Gwei::plus); } @@ -666,117 +599,6 @@ default UInt64 integer_squareroot(UInt64 n) { return x; } - /* - def is_power_of_two(value: int) -> bool: - """ - Check if ``value`` is a power of two integer. - """ - if value == 0: - return False - else: - return 2**int(math.log2(value)) == value - */ - default boolean is_power_of_two(UInt64 value) { - return Long.bitCount(value.getValue()) == 1; - } - - /* - def process_deposit(state: BeaconState, deposit: Deposit) -> None: - """ - Process a deposit from Ethereum 1.0. - Note that this function mutates ``state``. - """ - */ - default void process_deposit( - MutableBeaconState state, - Deposit deposit) { - process_deposit_inner(state, deposit, isBlsVerifyProofOfPossession()); - } - /* - def process_deposit(state: BeaconState, deposit: Deposit) -> None: - """ - Process a deposit from Ethereum 1.0. - Note that this function mutates ``state``. - """ - */ - - default void process_deposit_inner( - MutableBeaconState state, - Deposit deposit, - boolean verifyProof) { - - /* deposit_input = deposit.deposit_data.deposit_input */ - DepositInput deposit_input = deposit.getDepositData().getDepositInput(); - - /* - # Increment the next deposit index we are expecting. Note that this - # needs to be done here because while the deposit contract will never - # create an invalid Merkle branch, it may admit an invalid deposit - # object, and we need to be able to skip over it - state.deposit_index += 1 - */ - state.setDepositIndex(state.getDepositIndex().increment()); - - /* - validator_pubkeys = [v.pubkey for v in state.validator_registry] - pubkey = deposit_input.pubkey - amount = deposit.deposit_data.amount - withdrawal_credentials = deposit_input.withdrawal_credentials - */ - BLSPubkey pubkey = deposit_input.getPubKey(); - Gwei amount = deposit.getDepositData().getAmount(); - Hash32 withdrawal_credentials = deposit_input.getWithdrawalCredentials(); - ValidatorIndex index = get_validator_index_by_pubkey(state, pubkey); - - // if pubkey not in validator_pubkeys: - if (index.equals(ValidatorIndex.MAX)) { - /* - # Verify the proof of possession - proof_is_valid = bls_verify( - pubkey=deposit_input.pubkey, - message_hash=signed_root(deposit_input), - signature=deposit_input.proof_of_possession, - domain=get_domain( - state.fork, - get_current_epoch(state), - DOMAIN_DEPOSIT, - ) - ) - if not proof_is_valid: - return */ - - boolean proof_is_valid = - !verifyProof - || bls_verify( - deposit_input.getPubKey(), - signed_root(deposit_input), - deposit_input.getProofOfPossession(), - get_domain(state.getFork(), get_current_epoch(state), SignatureDomains.DEPOSIT)); - - if (!proof_is_valid) { - return; - } - - // Add new validator - ValidatorRecord validator = new ValidatorRecord( - pubkey, - withdrawal_credentials, - getConstants().getFarFutureEpoch(), - getConstants().getFarFutureEpoch(), - getConstants().getFarFutureEpoch(), - Boolean.FALSE, - Boolean.FALSE); - - // Note: In phase 2 registry indices that have been withdrawn for a long time will be - // recycled. - state.getValidatorRegistry().add(validator); - state.getValidatorBalances().add(amount); - } else { - // Increase balance by deposit amount - state.getValidatorBalances().update(index, oldBalance -> oldBalance.plus(amount)); - } - } - /* def get_delayed_activation_exit_epoch(epoch: EpochNumber) -> EpochNumber: """ @@ -790,133 +612,111 @@ default EpochNumber get_delayed_activation_exit_epoch(EpochNumber epoch) { } /* - def activate_validator(state: BeaconState, index: int, genesis: bool) -> None: - validator = state.validator_registry[index] - - validator.activation_slot = GENESIS_SLOT if genesis else (state.slot + ACTIVATION_EXIT_DELAY) - state.validator_registry_delta_chain_tip = hash_tree_root( - ValidatorRegistryDeltaBlock( - latest_registry_delta_root=state.validator_registry_delta_chain_tip, - validator_index=index, - pubkey=validator.pubkey, - slot=validator.activation_slot, - flag=ACTIVATION, - ) + def get_churn_limit(state: BeaconState) -> int: + return max( + MIN_PER_EPOCH_CHURN_LIMIT, + len(get_active_validator_indices(state, get_current_epoch(state))) // CHURN_LIMIT_QUOTIENT ) */ - default void activate_validator(MutableBeaconState state, ValidatorIndex index, boolean genesis) { - EpochNumber activationSlot = - genesis ? getConstants().getGenesisEpoch() : - get_delayed_activation_exit_epoch(get_current_epoch(state)); - state - .getValidatorRegistry() - .update(index, v -> v.builder().withActivationEpoch(activationSlot).build()); + default UInt64 get_churn_limit(BeaconState state) { + return UInt64s.max( + getConstants().getMinPerEpochChurnLimit(), + UInt64.valueOf(get_active_validator_indices(state, get_current_epoch(state)).size()) + .dividedBy(getConstants().getChurnLimitQuotient()) + ); } /* - def slash_validator(state: BeaconState, index: ValidatorIndex) -> None: - """ - Slash the validator with index ``index``. - Note that this function mutates ``state``. - """ - validator = state.validator_registry[index] - assert state.slot < get_epoch_start_slot(validator.withdrawable_epoch) # [TO BE REMOVED IN PHASE 2] - exit_validator(state, index) - state.latest_slashed_balances[get_current_epoch(state) % LATEST_SLASHED_EXIT_LENGTH] += get_effective_balance(state, index) - - whistleblower_index = get_beacon_proposer_index(state, state.slot) - whistleblower_reward = get_effective_balance(state, index) // WHISTLEBLOWER_REWARD_QUOTIENT - state.validator_balances[whistleblower_index] += whistleblower_reward - state.validator_balances[index] -= whistleblower_reward - validator.slashed = True - validator.withdrawable_epoch = get_current_epoch(state) + LATEST_SLASHED_EXIT_LENGTH + def slash_validator(state: BeaconState, slashed_index: ValidatorIndex, whistleblower_index: ValidatorIndex=None) -> None: + """ + Slash the validator with index ``slashed_index``. + """ + current_epoch = get_current_epoch(state) + initiate_validator_exit(state, slashed_index) + state.validator_registry[slashed_index].slashed = True + state.validator_registry[slashed_index].withdrawable_epoch = current_epoch + LATEST_SLASHED_EXIT_LENGTH + slashed_balance = state.validator_registry[slashed_index].effective_balance + state.latest_slashed_balances[current_epoch % LATEST_SLASHED_EXIT_LENGTH] += slashed_balance + + proposer_index = get_beacon_proposer_index(state) + if whistleblower_index is None: + whistleblower_index = proposer_index + whistleblowing_reward = slashed_balance // WHISTLEBLOWING_REWARD_QUOTIENT + proposer_reward = whistleblowing_reward // PROPOSER_REWARD_QUOTIENT + increase_balance(state, proposer_index, proposer_reward) + increase_balance(state, whistleblower_index, whistleblowing_reward - proposer_reward) + decrease_balance(state, slashed_index, whistleblowing_reward) */ - default void slash_validator(MutableBeaconState state, ValidatorIndex index) { - ValidatorRecord validator = state.getValidatorRegistry().get(index); - assertTrue(state.getSlot().less(get_epoch_start_slot(validator.getWithdrawableEpoch()))); - exit_validator(state, index); - state.getLatestSlashedBalances().update( - get_current_epoch(state).modulo(getConstants().getLatestSlashedExitLength()), - balance -> balance.plus(get_effective_balance(state, index))); - - ValidatorIndex whistleblower_index = get_beacon_proposer_index(state, state.getSlot()); - Gwei whistleblower_reward = get_effective_balance(state, index) - .dividedBy(getConstants().getWhistleblowerRewardQuotient()); - state.getValidatorBalances().update(whistleblower_index, - oldVal -> oldVal.plus(whistleblower_reward)); - state.getValidatorBalances().update(index, - oldVal -> oldVal.minus(whistleblower_reward)); - state.getValidatorRegistry().update(index, - v -> v.builder().withSlashed(Boolean.TRUE) - .withWithdrawableEpoch(get_current_epoch(state).plus(getConstants().getLatestSlashedExitLength())) - .build()); + default void slash_validator(MutableBeaconState state, ValidatorIndex slashed_index, ValidatorIndex whistleblower_index) { + EpochNumber current_epoch = get_current_epoch(state); + initiate_validator_exit(state, slashed_index); + state.getValidatorRegistry().update(slashed_index, + validator -> ValidatorRecord.Builder.fromRecord(validator) + .withSlashed(Boolean.TRUE) + .withWithdrawableEpoch(current_epoch.plus(getConstants().getLatestSlashedExitLength())).build()); + Gwei slashed_balance = state.getValidatorRegistry().get(slashed_index).getEffectiveBalance(); + state.getLatestSlashedBalances().update(current_epoch.modulo(getConstants().getLatestSlashedExitLength()), + balance -> balance.plus(slashed_balance)); + + ValidatorIndex proposer_index = get_beacon_proposer_index(state); + if (whistleblower_index == null) { + whistleblower_index = proposer_index; + } + Gwei whistleblowing_reward = slashed_balance.dividedBy(getConstants().getWhistleblowingRewardQuotient()); + Gwei proposer_reward = whistleblowing_reward.dividedBy(getConstants().getProposerRewardQuotient()); + increase_balance(state, proposer_index, proposer_reward); + increase_balance(state, whistleblower_index, whistleblowing_reward); + decrease_balance(state, slashed_index, whistleblowing_reward); } - /* - def initiate_validator_exit(state: BeaconState, index: int) -> None: - validator = state.validator_registry[index] - validator.initiated_exit = True - */ - default void initiate_validator_exit(MutableBeaconState state, ValidatorIndex index) { - state - .getValidatorRegistry() - .update( - index, - v -> - v.builder() - .withInitiatedExit(Boolean.TRUE) - .build()); + default void slash_validator(MutableBeaconState state, ValidatorIndex slashed_index) { + slash_validator(state, slashed_index, null); } /* - def exit_validator(state: BeaconState, index: ValidatorIndex) -> None: + def initiate_validator_exit(state: BeaconState, index: ValidatorIndex) -> None: """ - Exit the validator of the given ``index``. - Note that this function mutates ``state``. + Initiate the validator of the given ``index``. """ + */ + default void initiate_validator_exit(MutableBeaconState state, ValidatorIndex index) { + /* # Return if validator already initiated exit validator = state.validator_registry[index] - delayed_activation_exit_epoch = get_delayed_activation_exit_epoch(get_current_epoch(state)) - - # The following updates only occur if not previous exited - if validator.exit_epoch <= delayed_activation_exit_epoch: - return - else: - validator.exit_epoch = delayed_activation_exit_epoch - */ - default void exit_validator(MutableBeaconState state, ValidatorIndex index) { - ValidatorRecord validator = state.getValidatorRegistry().get(index); - EpochNumber delayed_activation_exit_epoch = - get_delayed_activation_exit_epoch(get_current_epoch(state)); - - // The following updates only occur if not previous exited - if (validator.getExitEpoch().lessEqual(delayed_activation_exit_epoch)) { + if validator.exit_epoch != FAR_FUTURE_EPOCH: + return */ + checkIndexRange(state, index); + if (!state.getValidatorRegistry().get(index).getExitEpoch().equals(getConstants().getFarFutureEpoch())) { return; - } else { - state.getValidatorRegistry().update(index, v -> - v.builder().withExitEpoch(delayed_activation_exit_epoch).build()); } - } - /* - def prepare_validator_for_withdrawal(state: BeaconState, index: ValidatorIndex) -> None: - """ - Set the validator with the given ``index`` as withdrawable - ``MIN_VALIDATOR_WITHDRAWABILITY_DELAY`` after the current epoch. - Note that this function mutates ``state``. - """ - validator = state.validator_registry[index] - validator.withdrawable_epoch = get_current_epoch(state) + MIN_VALIDATOR_WITHDRAWABILITY_DELAY - */ - default void prepare_validator_for_withdrawal(MutableBeaconState state, ValidatorIndex index) { - state - .getValidatorRegistry() - .update( - index, - v -> - v.builder() - .withWithdrawableEpoch( - get_current_epoch(state).plus(getConstants().getMinValidatorWithdrawabilityDelay())) - .build()); + /* # Compute exit queue epoch + exit_epochs = [v.exit_epoch for v in state.validator_registry if v.exit_epoch != FAR_FUTURE_EPOCH] + exit_queue_epoch = max(exit_epochs + [get_delayed_activation_exit_epoch(get_current_epoch(state))]) + exit_queue_churn = len([v for v in state.validator_registry if v.exit_epoch == exit_queue_epoch]) + if exit_queue_churn >= get_churn_limit(state): + exit_queue_epoch += 1 */ + EpochNumber exit_queue_epoch = Stream.concat( + state.getValidatorRegistry().stream() + .filter(v -> !v.getExitEpoch().equals(getConstants().getFarFutureEpoch())) + .map(ValidatorRecord::getExitEpoch), + Stream.of(get_delayed_activation_exit_epoch(get_current_epoch(state))) + ).max(EpochNumber::compareTo).get(); + + long exit_queue_churn = state.getValidatorRegistry().stream() + .filter(v -> v.getExitEpoch().equals(exit_queue_epoch)) + .count(); + if (UInt64.valueOf(exit_queue_churn).compareTo(get_churn_limit(state)) >= 0) { + exit_queue_epoch.increment(); + } + + /* # Set validator exit epoch and withdrawable epoch + validator.exit_epoch = exit_queue_epoch + validator.withdrawable_epoch = validator.exit_epoch + MIN_VALIDATOR_WITHDRAWABILITY_DELAY */ + state.getValidatorRegistry().update(index, + validator -> ValidatorRecord.Builder.fromRecord(validator) + .withExitEpoch(exit_queue_epoch) + .withWithdrawableEpoch(validator.getExitEpoch().plus(getConstants().getMinValidatorWithdrawabilityDelay())) + .build()); } /** Function for hashing objects into a single root utilizing a hash tree structure */ @@ -925,26 +725,23 @@ default Hash32 hash_tree_root(Object object) { } /** Function for hashing self-signed objects */ - default Hash32 signed_root(Object object) { + default Hash32 signing_root(Object object) { return getObjectHasher().getHashTruncateLast(object); } /* def get_active_index_root(state: BeaconState, - epoch: EpochNumber) -> Bytes32: - """ - Return the index root at a recent ``epoch``. - """ - assert get_current_epoch(state) - LATEST_ACTIVE_INDEX_ROOTS_LENGTH + ACTIVATION_EXIT_DELAY < epoch - <= get_current_epoch(state) + ACTIVATION_EXIT_DELAY - return state.latest_active_index_roots[epoch % LATEST_ACTIVE_INDEX_ROOTS_LENGTH] + epoch: Epoch) -> Bytes32: + """ + Return the index root at a recent ``epoch``. + ``epoch`` expected to be between + (current_epoch - LATEST_ACTIVE_INDEX_ROOTS_LENGTH + ACTIVATION_EXIT_DELAY, current_epoch + ACTIVATION_EXIT_DELAY]. + """ + return state.latest_active_index_roots[epoch % LATEST_ACTIVE_INDEX_ROOTS_LENGTH] */ default Hash32 get_active_index_root(BeaconState state, EpochNumber epoch) { - assertTrue(get_current_epoch(state).minus(getConstants().getLatestActiveIndexRootsLength()).plus( - getConstants().getActivationExitDelay()) - .less(epoch)); - assertTrue(epoch.lessEqual(get_current_epoch(state).plus(getConstants().getActivationExitDelay()))); - return state.getLatestActiveIndexRoots().get(epoch.modulo(getConstants().getLatestActiveIndexRootsLength())); + return state.getLatestActiveIndexRoots().get( + epoch.modulo(getConstants().getLatestActiveIndexRootsLength())); } /* @@ -954,16 +751,20 @@ def generate_seed(state: BeaconState, Generate a seed for the given ``epoch``. """ return hash( - get_randao_mix(state, epoch - MIN_SEED_LOOKAHEAD) + + get_randao_mix(state, epoch + LATEST_RANDAO_MIXES_LENGTH - MIN_SEED_LOOKAHEAD) + get_active_index_root(state, epoch) + int_to_bytes32(epoch) ) */ default Hash32 generate_seed(BeaconState state, EpochNumber epoch) { + EpochNumber randao_mix_epoch = epoch + .plus(getConstants().getLatestRandaoMixesLength()) + .minus(getConstants().getMinSeedLookahead()); return hash( - get_randao_mix(state, epoch.minus(getConstants().getMinSeedLookahead())) - .concat(get_active_index_root(state, epoch)) - .concat(int_to_bytes32(epoch))); + get_randao_mix(state, randao_mix_epoch) + .concat(get_active_index_root(state, epoch)) + .concat(int_to_bytes32(epoch)) + ); } default boolean bls_verify(BLSPubkey publicKey, Hash32 message, BLSSignature signature, UInt64 domain) { @@ -1001,78 +802,49 @@ default PublicKey bls_aggregate_pubkeys(List publicKeysBytes) { } /* - def get_fork_version(fork: Fork, - epoch: EpochNumber) -> bytes: - """ - Return the fork version of the given ``epoch``. - """ - if epoch < fork.epoch: - return fork.previous_version - else: - return fork.current_version + def get_domain(state: BeaconState, + domain_type: int, + message_epoch: int=None) -> int: + """ + Return the signature domain (fork version concatenated with domain type) of a message. + """ + epoch = get_current_epoch(state) if message_epoch is None else message_epoch + fork_version = state.fork.previous_version if epoch < state.fork.epoch else state.fork.current_version + return bytes_to_int(fork_version + int_to_bytes4(domain_type)) */ - default Bytes4 get_fork_version(Fork fork, EpochNumber epoch) { - if (epoch.less(fork.getEpoch())) { - return fork.getPreviousVersion(); - } else { - return fork.getCurrentVersion(); - } + default UInt64 get_domain(BeaconState state, UInt64 domain_type, EpochNumber message_epoch) { + EpochNumber epoch = message_epoch == null ? get_current_epoch(state) : message_epoch; + Bytes4 fork_version = epoch.less(state.getFork().getEpoch()) ? + state.getFork().getPreviousVersion() : state.getFork().getCurrentVersion(); + return get_domain(fork_version, domain_type); } - /* - def get_domain(fork: Fork, - epoch: Epoch, - domain_type: int) -> int: - """ - Get the domain number that represents the fork meta and signature domain. - """ - return bytes_to_int(get_fork_version(fork, epoch) + int_to_bytes4(domain_type)) - */ - default UInt64 get_domain(Fork fork, EpochNumber epoch, UInt64 domainType) { - return bytes_to_int(get_fork_version(fork, epoch).concat(int_to_bytes4(domainType))); + default UInt64 get_domain(BeaconState state, UInt64 domain_type) { + return get_domain(state, domain_type, null); } - /* - def is_double_vote(attestation_data_1: AttestationData, - attestation_data_2: AttestationData) -> bool - """ - Assumes ``attestation_data_1`` is distinct from ``attestation_data_2``. - Returns True if the provided ``AttestationData`` are slashable - due to a 'double vote'. - """ - target_epoch_1 = attestation_data_1.slot // SLOTS_PER_EPOCH - target_epoch_2 = attestation_data_2.slot // SLOTS_PER_EPOCH - return target_epoch_1 == target_epoch_2 - */ - default boolean is_double_vote( - AttestationData attestation_data_1, AttestationData attestation_data_2) { - EpochNumber target_epoch_1 = slot_to_epoch(attestation_data_1.getSlot()); - EpochNumber target_epoch_2 = slot_to_epoch(attestation_data_2.getSlot()); - return target_epoch_1.equals(target_epoch_2); + default UInt64 get_domain(Bytes4 fork_version, UInt64 domain_type) { + return bytes_to_int(fork_version.concat(int_to_bytes4(domain_type))); } /* - def is_surround_vote(attestation_data_1: AttestationData, - attestation_data_2: AttestationData) -> bool: - """ - Check if ``attestation_data_1`` surrounds ``attestation_data_2``. - """ - source_epoch_1 = attestation_data_1.source_epoch - source_epoch_2 = attestation_data_2.source_epoch - target_epoch_1 = slot_to_epoch(attestation_data_1.slot) - target_epoch_2 = slot_to_epoch(attestation_data_2.slot) - - return source_epoch_1 < source_epoch_2 and target_epoch_2 < target_epoch_1 - */ - default boolean is_surround_vote( - AttestationData attestation_data_1, AttestationData attestation_data_2) { - EpochNumber source_epoch_1 = attestation_data_1.getSourceEpoch(); - EpochNumber source_epoch_2 = attestation_data_2.getSourceEpoch(); - EpochNumber target_epoch_1 = slot_to_epoch(attestation_data_1.getSlot()); - EpochNumber target_epoch_2 = slot_to_epoch(attestation_data_2.getSlot()); - - return (source_epoch_1.less(source_epoch_2)) - && (target_epoch_2.less(target_epoch_1)); + def is_slashable_attestation_data(data_1: AttestationData, data_2: AttestationData) -> bool: + """ + Check if ``data_1`` and ``data_2`` are slashable according to Casper FFG rules. + """ + return ( + # Double vote + (data_1 != data_2 and data_1.target_epoch == data_2.target_epoch) or + # Surround vote + (data_1.source_epoch < data_2.source_epoch and data_2.target_epoch < data_1.target_epoch) + ) + */ + default boolean is_slashable_attestation_data(AttestationData data_1, AttestationData data_2) { + return + // Double vote + (!data_1.equals(data_2) && data_1.getTargetEpoch().equals(data_2.getTargetEpoch())) + // Surround vote + || (data_1.getSourceEpoch().less(data_2.getSourceEpoch()) && data_2.getTargetEpoch().less(data_1.getTargetEpoch())); } default List mapIndicesToPubKeys(BeaconState state, Iterable indices) { @@ -1085,92 +857,112 @@ default List mapIndicesToPubKeys(BeaconState state, Iterable bool: + def convert_to_indexed(state: BeaconState, attestation: Attestation) -> IndexedAttestation: """ - Verify validity of ``slashable_attestation`` fields. + Convert ``attestation`` to (almost) indexed-verifiable form. """ + attesting_indices = get_attesting_indices(state, attestation.data, attestation.aggregation_bitfield) + custody_bit_1_indices = get_attesting_indices(state, attestation.data, attestation.custody_bitfield) + custody_bit_0_indices = [index for index in attesting_indices if index not in custody_bit_1_indices] + + return IndexedAttestation( + custody_bit_0_indices=custody_bit_0_indices, + custody_bit_1_indices=custody_bit_1_indices, + data=attestation.data, + signature=attestation.signature, + ) */ - default boolean verify_slashable_attestation(BeaconState state, SlashableAttestation slashable_attestation) { - // if slashable_attestation.custody_bitfield != b'\x00' * len(slashable_attestation.custody_bitfield): # [TO BE REMOVED IN PHASE 1] - // return False - if (!slashable_attestation.getCustodyBitfield().isZero()) return false; - - // if len(slashable_attestation.validator_indices) == 0: - // return False - if (slashable_attestation.getValidatorIndices().size() == 0) return false; - - // for i in range(len(slashable_attestation.validator_indices) - 1): - // if slashable_attestation.validator_indices[i] >= slashable_attestation.validator_indices[i + 1]: - // return False - - for (int i = 0; i < slashable_attestation.getValidatorIndices().size() - 1; i++) { - if (slashable_attestation.getValidatorIndices().get(i).greaterEqual( - slashable_attestation.getValidatorIndices().get(i + 1))) { - return false; - } - } + default IndexedAttestation convert_to_indexed(BeaconState state, Attestation attestation) { + List attesting_indices = + get_attesting_indices(state, attestation.getData(), attestation.getAggregationBitfield()); + List custody_bit_1_indices = + get_attesting_indices(state, attestation.getData(), attestation.getCustodyBitfield()); + List custody_bit_0_indices = attesting_indices.stream() + .filter(index -> !custody_bit_1_indices.contains(index)).collect(toList()); + + return new IndexedAttestation( + custody_bit_0_indices, + custody_bit_1_indices, + attestation.getData(), + attestation.getSignature()); + } + + /* + def verify_indexed_attestation(state: BeaconState, indexed_attestation: IndexedAttestation) -> bool: + """ + Verify validity of ``indexed_attestation`` fields. + """ + */ + default boolean verify_indexed_attestation(BeaconState state, IndexedAttestation indexed_attestation) { + /* + custody_bit_0_indices = indexed_attestation.custody_bit_0_indices + custody_bit_1_indices = indexed_attestation.custody_bit_1_indices + */ + ReadList custody_bit_0_indices = indexed_attestation.getCustodyBit0Indices(); + ReadList custody_bit_1_indices = indexed_attestation.getCustodyBit1Indices(); + + // Ensure no duplicate indices across custody bits + assertTrue(custody_bit_0_indices.intersection(custody_bit_1_indices).size() == 0); - // if not verify_bitfield(slashable_attestation.custody_bitfield, len(slashable_attestation.validator_indices)): - // return False - if (!verify_bitfield(slashable_attestation.getCustodyBitfield(), slashable_attestation.getValidatorIndices().size())) { + /* + if len(custody_bit_1_indices) > 0: # [TO BE REMOVED IN PHASE 1] + return False + */ + if (custody_bit_1_indices.size() > 0) { return false; } - // if len(slashable_attestation.validator_indices) > MAX_INDICES_PER_SLASHABLE_VOTE: - // return False - if (UInt64.valueOf(slashable_attestation.getValidatorIndices().size()). - compareTo(getConstants().getMaxIndicesPerSlashableVote()) > 0) { + /* + if not (1 <= len(custody_bit_0_indices) + len(custody_bit_1_indices) <= MAX_INDICES_PER_ATTESTATION): + return False + */ + int indices_in_total = custody_bit_0_indices.size() + custody_bit_1_indices.size(); + if (indices_in_total < 1 + || indices_in_total > getConstants().getMaxIndicesPerAttestation().getIntValue()) { return false; } /* - custody_bit_0_indices = [] - custody_bit_1_indices = [] - for i, validator_index in enumerate(slashable_attestation.validator_indices): - if get_bitfield_bit(slashable_attestation.custody_bitfield, i) == 0b0: - custody_bit_0_indices.append(validator_index) - else: - custody_bit_1_indices.append(validator_index) - */ - List custody_bit_0_indices = new ArrayList<>(); - List custody_bit_1_indices = new ArrayList<>(); - for (int i = 0; i < slashable_attestation.getValidatorIndices().size(); i++) { - ValidatorIndex validator_index = slashable_attestation.getValidatorIndices().get(i); - if (slashable_attestation.getCustodyBitfield().getBit(i) == false) { - custody_bit_0_indices.add(validator_index); - } else { - custody_bit_1_indices.add(validator_index); - } + if custody_bit_0_indices != sorted(custody_bit_0_indices): + return False + if custody_bit_1_indices != sorted(custody_bit_1_indices): + return False + */ + if (!Ordering.natural().isOrdered(custody_bit_0_indices)) { + return false; + } + + if (!Ordering.natural().isOrdered(custody_bit_1_indices)) { + return false; } /* - return bls_verify( + return bls_verify_multiple( pubkeys=[ bls_aggregate_pubkeys([state.validator_registry[i].pubkey for i in custody_bit_0_indices]), bls_aggregate_pubkeys([state.validator_registry[i].pubkey for i in custody_bit_1_indices]), ], - messages=[ - hash_tree_root(AttestationDataAndCustodyBit(data=slashable_attestation.data, custody_bit=0b0)), - hash_tree_root(AttestationDataAndCustodyBit(data=slashable_attestation.data, custody_bit=0b1)), + message_hashes=[ + hash_tree_root(AttestationDataAndCustodyBit(data=indexed_attestation.data, custody_bit=0b0)), + hash_tree_root(AttestationDataAndCustodyBit(data=indexed_attestation.data, custody_bit=0b1)), ], - signature=slashable_attestation.aggregate_signature, - domain=get_domain( - state.fork, - slot_to_epoch(vote_data.data.slot), - DOMAIN_ATTESTATION, - ), + signature=indexed_attestation.signature, + domain=get_domain(state, DOMAIN_ATTESTATION, slot_to_epoch(indexed_attestation.data.slot)), ) - */ - List pubKeys1 = mapIndicesToPubKeys(state, custody_bit_0_indices); - List pubKeys2 = mapIndicesToPubKeys(state, custody_bit_1_indices); - + */ return bls_verify_multiple( - Arrays.asList(bls_aggregate_pubkeys(pubKeys1), bls_aggregate_pubkeys(pubKeys2)), Arrays.asList( - hash_tree_root(new AttestationDataAndCustodyBit(slashable_attestation.getData(), false)), - hash_tree_root(new AttestationDataAndCustodyBit(slashable_attestation.getData(), true))), - slashable_attestation.getAggregateSingature(), - get_domain(state.getFork(), slot_to_epoch(slashable_attestation.getData().getSlot()), ATTESTATION)); + bls_aggregate_pubkeys(custody_bit_0_indices.stream() + .map(i -> state.getValidatorRegistry().get(i).getPubKey()).collect(Collectors.toList())), + bls_aggregate_pubkeys(custody_bit_1_indices.stream() + .map(i -> state.getValidatorRegistry().get(i).getPubKey()).collect(Collectors.toList()))), + Arrays.asList( + hash_tree_root(new AttestationDataAndCustodyBit(indexed_attestation.getData(), false)), + hash_tree_root(new AttestationDataAndCustodyBit(indexed_attestation.getData(), true)) + ), + indexed_attestation.getSignature(), + get_domain(state, ATTESTATION, indexed_attestation.getData().getTargetEpoch()) + ); } /* @@ -1205,81 +997,57 @@ default boolean verify_bitfield(Bitfield bitfield, int committee_size) { } /* - def get_block_root(state: BeaconState, - slot: Slot) -> Bytes32: - """ - Return the block root at a recent ``slot``. - """ - assert slot < state.slot <= slot + SLOTS_PER_HISTORICAL_ROOT - return state.latest_block_roots[slot % SLOTS_PER_HISTORICAL_ROOT] + def get_block_root_at_slot(state: BeaconState, + slot: Slot) -> Bytes32: + """ + Return the block root at a recent ``slot``. + """ + assert slot < state.slot <= slot + SLOTS_PER_HISTORICAL_ROOT + return state.latest_block_roots[slot % SLOTS_PER_HISTORICAL_ROOT] */ - default Hash32 get_block_root(BeaconState state, SlotNumber slot) { - assertTrue(state.getSlot().lessEqual(slot.plus(getConstants().getSlotsPerHistoricalRoot()))); + default Hash32 get_block_root_at_slot(BeaconState state, SlotNumber slot) { assertTrue(slot.less(state.getSlot())); + assertTrue(state.getSlot().lessEqual(slot.plus(getConstants().getSlotsPerHistoricalRoot()))); return state.getLatestBlockRoots().get(slot.modulo(getConstants().getSlotsPerHistoricalRoot())); } /* - def get_state_root(state: BeaconState, - slot: Slot) -> Bytes32: + def get_block_root(state: BeaconState, + epoch: Epoch) -> Bytes32: """ - Return the state root at a recent ``slot``. + Return the block root at a recent ``epoch``. """ - assert slot < state.slot <= slot + SLOTS_PER_HISTORICAL_ROOT - return state.latest_state_roots[slot % SLOTS_PER_HISTORICAL_ROOT] + return get_block_root_at_slot(state, get_epoch_start_slot(epoch)) */ - default Hash32 get_state_root(BeaconState state, SlotNumber slot) { - assertTrue(state.getSlot().lessEqual(slot.plus(getConstants().getSlotsPerHistoricalRoot()))); - assertTrue(slot.less(state.getSlot())); - return state.getLatestStateRoots().get(slot.modulo(getConstants().getSlotsPerHistoricalRoot())); + default Hash32 get_block_root(BeaconState state, EpochNumber epoch) { + return get_block_root_at_slot(state, get_epoch_start_slot(epoch)); } /* - def get_attestation_participants(state: BeaconState, - attestation_data: AttestationData, - bitfield: bytes) -> List[ValidatorIndex]: + def get_attesting_indices(state: BeaconState, + attestation_data: AttestationData, + bitfield: bytes) -> List[ValidatorIndex]: """ - Return the participant indices at for the ``attestation_data`` and ``bitfield``. + Return the sorted attesting indices corresponding to ``attestation_data`` and ``bitfield``. """ - # Find the committee in the list with the desired shard - crosslink_committees = get_crosslink_committees_at_slot(state, attestation_data.slot) - - assert attestation_data.shard in [shard for _, shard in crosslink_committees] - crosslink_committee = [committee for committee, shard in crosslink_committees if shard == attestation_data.shard][0] - - assert verify_bitfield(bitfield, len(crosslink_committee)) - - # Find the participating attesters in the committee - participants = [] - for i, validator_index in enumerate(crosslink_committee): - aggregation_bit = get_bitfield_bit(bitfield, i) - if aggregation_bit == 0b1: - participants.append(validator_index) - return participants + committee = get_crosslink_committee(state, attestation_data.target_epoch, attestation_data.shard) + assert verify_bitfield(bitfield, len(committee)) + return sorted([index for i, index in enumerate(committee) if get_bitfield_bit(bitfield, i) == 0b1]) */ - default List get_attestation_participants( + default List get_attesting_indices( BeaconState state, AttestationData attestation_data, Bitfield bitfield) { - List crosslink_committees = - get_crosslink_committees_at_slot(state, attestation_data.getSlot()); - - assertTrue(crosslink_committees.stream() - .anyMatch(cc -> attestation_data.getShard().equals(cc.getShard()))); - Optional crosslink_committee_opt = - crosslink_committees.stream() - .filter(committee -> committee.getShard().equals(attestation_data.getShard())) - .findFirst(); - assertTrue(crosslink_committee_opt.isPresent()); - List crosslink_committee = crosslink_committee_opt.get().getCommittee(); - assertTrue(verify_bitfield(bitfield, crosslink_committee.size())); - + List committee = + get_crosslink_committee(state, attestation_data.getTargetEpoch(), attestation_data.getShard()); + assertTrue(verify_bitfield(bitfield, committee.size())); List participants = new ArrayList<>(); - for (int i = 0; i < crosslink_committee.size(); i++) { - ValidatorIndex validator_index = crosslink_committee.get(i); + for (int i = 0; i < committee.size(); i++) { + ValidatorIndex validator_index = committee.get(i); boolean aggregation_bit = bitfield.getBit(i); if (aggregation_bit) { participants.add(validator_index); } } + participants.sort(UInt64::compareTo); return participants; } @@ -1308,11 +1076,15 @@ default EpochNumber slot_to_epoch(SlotNumber slot) { def get_previous_epoch(state: BeaconState) -> Epoch: """` Return the previous epoch of the given ``state``. + Return the current epoch if it's genesis epoch. """ - return get_current_epoch(state) - 1 + current_epoch = get_current_epoch(state) + return (current_epoch - 1) if current_epoch > GENESIS_EPOCH else current_epoch */ default EpochNumber get_previous_epoch(BeaconState state) { - return get_current_epoch(state).decrement(); + EpochNumber current_epoch = get_current_epoch(state); + return current_epoch.greater(getConstants().getGenesisEpoch()) ? + current_epoch.decrement() : current_epoch; } /* diff --git a/consensus/src/main/java/org/ethereum/beacon/consensus/spec/OnGenesis.java b/consensus/src/main/java/org/ethereum/beacon/consensus/spec/OnGenesis.java index 7ec559fea..99e7ad205 100644 --- a/consensus/src/main/java/org/ethereum/beacon/consensus/spec/OnGenesis.java +++ b/consensus/src/main/java/org/ethereum/beacon/consensus/spec/OnGenesis.java @@ -12,22 +12,26 @@ import org.ethereum.beacon.core.operations.attestation.Crosslink; import org.ethereum.beacon.core.state.Eth1Data; import org.ethereum.beacon.core.state.Fork; +import org.ethereum.beacon.core.state.ValidatorRecord; +import org.ethereum.beacon.core.types.BLSSignature; import org.ethereum.beacon.core.types.Bitfield64; import org.ethereum.beacon.core.types.EpochNumber; import org.ethereum.beacon.core.types.Gwei; +import org.ethereum.beacon.core.types.ShardNumber; import org.ethereum.beacon.core.types.Time; import org.ethereum.beacon.core.types.ValidatorIndex; import tech.pegasys.artemis.ethereum.core.Hash32; +import tech.pegasys.artemis.util.bytes.Bytes32; import tech.pegasys.artemis.util.uint.UInt64; /** * On genesis part. * * @see On + * href="https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#on-genesis">On * genesis in the spec. */ -public interface OnGenesis extends HelperFunction { +public interface OnGenesis extends BlockProcessing { /* """ @@ -36,9 +40,10 @@ public interface OnGenesis extends HelperFunction { */ default BeaconBlock get_empty_block() { BeaconBlockBody body = - new BeaconBlockBody( - getConstants().getEmptySignature(), - new Eth1Data(Hash32.ZERO, Hash32.ZERO), + BeaconBlockBody.create( + BLSSignature.ZERO, + new Eth1Data(Hash32.ZERO, UInt64.ZERO, Hash32.ZERO), + Bytes32.ZERO, emptyList(), emptyList(), emptyList(), @@ -46,7 +51,7 @@ default BeaconBlock get_empty_block() { emptyList(), emptyList()); return new BeaconBlock( - getConstants().getGenesisSlot(), Hash32.ZERO, Hash32.ZERO, body, getConstants().getEmptySignature()); + getConstants().getGenesisSlot(), Hash32.ZERO, Hash32.ZERO, body, BLSSignature.ZERO); } /* @@ -62,23 +67,17 @@ default BeaconState get_genesis_beacon_state( state.setSlot(getConstants().getGenesisSlot()); state.setGenesisTime(genesisTime); state.setFork(new Fork( - int_to_bytes4(getConstants().getGenesisForkVersion()), - int_to_bytes4(getConstants().getGenesisForkVersion()), + int_to_bytes4(UInt64.ZERO), + int_to_bytes4(UInt64.ZERO), getConstants().getGenesisEpoch())); // Validator registry state.getValidatorRegistry().clear(); - state.getValidatorBalances().clear(); - state.setValidatorRegistryUpdateEpoch(getConstants().getGenesisEpoch()); + state.getBalances().clear(); // Randomness and committees state.getLatestRandaoMixes().setAll(Hash32.ZERO); - state.setPreviousShufflingStartShard(getConstants().getGenesisStartShard()); - state.setCurrentShufflingStartShard(getConstants().getGenesisStartShard()); - state.setPreviousShufflingEpoch(getConstants().getGenesisEpoch()); - state.setCurrentShufflingEpoch(getConstants().getGenesisEpoch()); - state.setPreviousShufflingSeed(Hash32.ZERO); - state.setCurrentShufflingSeed(Hash32.ZERO); + state.setLatestStartShard(ShardNumber.ZERO); // Finality state.getPreviousEpochAttestations().clear(); @@ -92,12 +91,8 @@ default BeaconState get_genesis_beacon_state( state.setFinalizedRoot(Hash32.ZERO); // Recent state - state.getPreviousCrosslinks().addAll( - nCopies(getConstants().getShardCount().getIntValue(), - new Crosslink(getConstants().getGenesisEpoch(), Hash32.ZERO))); - state.getCurrentCrosslinks().addAll( - nCopies(getConstants().getShardCount().getIntValue(), - new Crosslink(getConstants().getGenesisEpoch(), Hash32.ZERO))); + state.getPreviousCrosslinks().setAll(Crosslink.EMPTY); + state.getCurrentCrosslinks().setAll(Crosslink.EMPTY); state.getLatestBlockRoots().setAll(Hash32.ZERO); state.getLatestStateRoots().setAll(Hash32.ZERO); state.getLatestActiveIndexRoots().setAll(Hash32.ZERO); @@ -117,18 +112,21 @@ default BeaconState get_genesis_beacon_state( // Process genesis activations for (ValidatorIndex validatorIndex : state.getValidatorRegistry().size().iterateFromZero()) { - if (get_effective_balance(state, validatorIndex).greaterEqual(getConstants().getMaxDepositAmount())) { - activate_validator(state, validatorIndex, true); + ValidatorRecord validator = state.getValidatorRegistry().get(validatorIndex); + if (validator.getEffectiveBalance().greaterEqual(getConstants().getMaxEffectiveBalance())) { + state.getValidatorRegistry().update(validatorIndex, + record -> ValidatorRecord.Builder.fromRecord(record) + .withActivationEpoch(getConstants().getGenesisEpoch()) + .withActivationEligibilityEpoch(getConstants().getGenesisEpoch()).build()); } } Hash32 genesisActiveIndexRoot = hash_tree_root( - get_active_validator_indices(state.getValidatorRegistry(), getConstants().getGenesisEpoch())); + get_active_validator_indices(state, getConstants().getGenesisEpoch())); for (EpochNumber index : getConstants().getLatestActiveIndexRootsLength().iterateFrom(EpochNumber.ZERO)) { state.getLatestActiveIndexRoots().set(index, genesisActiveIndexRoot); } - state.setCurrentShufflingSeed(generate_seed(state, getConstants().getGenesisEpoch())); return state.createImmutable(); } diff --git a/consensus/src/main/java/org/ethereum/beacon/consensus/spec/SlotProcessing.java b/consensus/src/main/java/org/ethereum/beacon/consensus/spec/SlotProcessing.java index 04bc241c1..0db210c6b 100644 --- a/consensus/src/main/java/org/ethereum/beacon/consensus/spec/SlotProcessing.java +++ b/consensus/src/main/java/org/ethereum/beacon/consensus/spec/SlotProcessing.java @@ -6,7 +6,7 @@ * Per slot processing. * * @see Per-slot + * href="https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#per-slot-processing">Per-slot * processing in the spec. */ public interface SlotProcessing extends HelperFunction { diff --git a/consensus/src/main/java/org/ethereum/beacon/consensus/spec/StateCaching.java b/consensus/src/main/java/org/ethereum/beacon/consensus/spec/StateCaching.java index 1e84d0fa4..07867147e 100644 --- a/consensus/src/main/java/org/ethereum/beacon/consensus/spec/StateCaching.java +++ b/consensus/src/main/java/org/ethereum/beacon/consensus/spec/StateCaching.java @@ -1,5 +1,6 @@ package org.ethereum.beacon.consensus.spec; +import org.ethereum.beacon.core.BeaconBlockHeader; import org.ethereum.beacon.core.MutableBeaconState; import tech.pegasys.artemis.ethereum.core.Hash32; @@ -7,7 +8,7 @@ * State caching. * * @see State + * href="https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#state-caching">State * caching in the spec. */ public interface StateCaching extends HelperFunction { @@ -17,21 +18,33 @@ public interface StateCaching extends HelperFunction { Note: this function mutates beacon state */ default void cache_state(MutableBeaconState state) { - Hash32 previousSlotStateRoot = hash_tree_root(state); + /* # Cache latest known state root (for previous slot) + latest_state_root = hash_tree_root(state) + state.latest_state_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = latest_state_root */ + Hash32 latest_state_root = hash_tree_root(state); + state.getLatestStateRoots().update( + state.getSlot().modulo(getConstants().getSlotsPerHistoricalRoot()), + root -> latest_state_root); - // store the previous slot's post state transition root - state.getLatestStateRoots() - .set(state.getSlot().modulo(getConstants().getSlotsPerHistoricalRoot()), previousSlotStateRoot); - - // cache state root in stored latest_block_header if empty + /* # Store latest known state root (for previous slot) in latest_block_header if it is empty + if state.latest_block_header.state_root == ZERO_HASH: + state.latest_block_header.state_root = latest_state_root */ if (state.getLatestBlockHeader().getStateRoot().equals(Hash32.ZERO)) { - state.setLatestBlockHeader(state.getLatestBlockHeader().withStateRoot(previousSlotStateRoot)); + state.setLatestBlockHeader(new BeaconBlockHeader( + state.getLatestBlockHeader().getSlot(), + state.getLatestBlockHeader().getPreviousBlockRoot(), + latest_state_root, + state.getLatestBlockHeader().getBlockBodyRoot(), + state.getLatestBlockHeader().getSignature() + )); } - // store latest known block for previous slot - state.getLatestBlockRoots() - .set( - state.getSlot().modulo(getConstants().getSlotsPerHistoricalRoot()), - signed_root(state.getLatestBlockHeader())); + /* # Cache latest known block root (for previous slot) + latest_block_root = signing_root(state.latest_block_header) + state.latest_block_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = latest_block_root */ + Hash32 latest_block_root = signing_root(state.getLatestBlockHeader()); + state.getLatestBlockRoots().update( + state.getSlot().modulo(getConstants().getSlotsPerHistoricalRoot()), + root -> latest_block_root); } } diff --git a/consensus/src/main/java/org/ethereum/beacon/consensus/transition/BeaconStateExImpl.java b/consensus/src/main/java/org/ethereum/beacon/consensus/transition/BeaconStateExImpl.java index 39b3cc7b7..7e5c2a50c 100644 --- a/consensus/src/main/java/org/ethereum/beacon/consensus/transition/BeaconStateExImpl.java +++ b/consensus/src/main/java/org/ethereum/beacon/consensus/transition/BeaconStateExImpl.java @@ -4,7 +4,6 @@ import org.ethereum.beacon.consensus.TransitionType; import org.ethereum.beacon.core.BeaconState; import org.ethereum.beacon.ssz.annotation.SSZSerializable; -import tech.pegasys.artemis.ethereum.core.Hash32; /** * Class to hold additional state info which is not included to the @@ -36,4 +35,19 @@ public TransitionType getTransition() { public String toString() { return toString(null, null); } + + @Override + public boolean equals(Object o) { + if (!super.equals(o)) { + return false; + } + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + BeaconStateExImpl that = (BeaconStateExImpl) o; + return lastTransition == that.lastTransition; + } } diff --git a/consensus/src/main/java/org/ethereum/beacon/consensus/transition/DelegateBeaconState.java b/consensus/src/main/java/org/ethereum/beacon/consensus/transition/DelegateBeaconState.java index 7115c2290..5dea1abc9 100644 --- a/consensus/src/main/java/org/ethereum/beacon/consensus/transition/DelegateBeaconState.java +++ b/consensus/src/main/java/org/ethereum/beacon/consensus/transition/DelegateBeaconState.java @@ -1,5 +1,6 @@ package org.ethereum.beacon.consensus.transition; +import com.google.common.base.Objects; import java.util.Map; import java.util.function.Supplier; import javax.annotation.Nullable; @@ -9,7 +10,6 @@ import org.ethereum.beacon.core.spec.SpecConstants; import org.ethereum.beacon.core.operations.attestation.Crosslink; import org.ethereum.beacon.core.state.Eth1Data; -import org.ethereum.beacon.core.state.Eth1DataVote; import org.ethereum.beacon.core.state.Fork; import org.ethereum.beacon.core.state.PendingAttestation; import org.ethereum.beacon.core.state.ValidatorRecord; @@ -69,13 +69,8 @@ public ReadList getValidatorRegistry() { } @Override - public ReadList getValidatorBalances() { - return delegate.getValidatorBalances(); - } - - @Override - public EpochNumber getValidatorRegistryUpdateEpoch() { - return delegate.getValidatorRegistryUpdateEpoch(); + public ReadList getBalances() { + return delegate.getBalances(); } @Override @@ -84,33 +79,8 @@ public ReadVector getLatestRandaoMixes() { } @Override - public ShardNumber getPreviousShufflingStartShard() { - return delegate.getPreviousShufflingStartShard(); - } - - @Override - public ShardNumber getCurrentShufflingStartShard() { - return delegate.getCurrentShufflingStartShard(); - } - - @Override - public EpochNumber getPreviousShufflingEpoch() { - return delegate.getPreviousShufflingEpoch(); - } - - @Override - public EpochNumber getCurrentShufflingEpoch() { - return delegate.getCurrentShufflingEpoch(); - } - - @Override - public Hash32 getPreviousShufflingSeed() { - return delegate.getPreviousShufflingSeed(); - } - - @Override - public Hash32 getCurrentShufflingSeed() { - return delegate.getCurrentShufflingSeed(); + public ShardNumber getLatestStartShard() { + return delegate.getLatestStartShard(); } @Override @@ -159,12 +129,12 @@ public Hash32 getFinalizedRoot() { } @Override - public ReadList getPreviousCrosslinks() { + public ReadVector getPreviousCrosslinks() { return delegate.getPreviousCrosslinks(); } @Override - public ReadList getCurrentCrosslinks() { + public ReadVector getCurrentCrosslinks() { return delegate.getCurrentCrosslinks(); } @@ -204,7 +174,7 @@ public Eth1Data getLatestEth1Data() { } @Override - public ReadList getEth1DataVotes() { + public ReadList getEth1DataVotes() { return delegate.getEth1DataVotes(); } @@ -222,4 +192,16 @@ public MutableBeaconState createMutableCopy() { public String toStringShort(@Nullable SpecConstants constants) { return delegate.toStringShort(constants); } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + DelegateBeaconState that = (DelegateBeaconState) o; + return Objects.equal(delegate, that.delegate); + } } diff --git a/consensus/src/main/java/org/ethereum/beacon/consensus/transition/ExtendedSlotTransition.java b/consensus/src/main/java/org/ethereum/beacon/consensus/transition/ExtendedSlotTransition.java index c728cf48a..cd3e51ced 100644 --- a/consensus/src/main/java/org/ethereum/beacon/consensus/transition/ExtendedSlotTransition.java +++ b/consensus/src/main/java/org/ethereum/beacon/consensus/transition/ExtendedSlotTransition.java @@ -17,7 +17,7 @@ * * * @see Beacon + * href="https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#beacon-chain-state-transition-function">Beacon * chain state transition function in the spec. * @see PerBlockTransition */ diff --git a/consensus/src/main/java/org/ethereum/beacon/consensus/transition/InitialStateTransition.java b/consensus/src/main/java/org/ethereum/beacon/consensus/transition/InitialStateTransition.java index 72c936c2a..4158fee91 100644 --- a/consensus/src/main/java/org/ethereum/beacon/consensus/transition/InitialStateTransition.java +++ b/consensus/src/main/java/org/ethereum/beacon/consensus/transition/InitialStateTransition.java @@ -20,7 +20,7 @@ * * @see DepositContract * @see On + * href="https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#on-genesis">On * genesis in the spec. */ public class InitialStateTransition implements BlockTransition { @@ -52,7 +52,7 @@ public BeaconStateEx apply(BeaconStateEx state, BeaconBlock block) { BeaconStateExImpl ret = new BeaconStateExImpl(genesisState, TransitionType.INITIAL); logger.debug(() -> "Slot transition result state: (" + - spec.hash_tree_root(ret).toStringShort() + ") " + ret.toString(spec.getConstants(), spec::signed_root)); + spec.hash_tree_root(ret).toStringShort() + ") " + ret.toString(spec.getConstants(), spec::signing_root)); return ret; } diff --git a/consensus/src/main/java/org/ethereum/beacon/consensus/transition/PerBlockTransition.java b/consensus/src/main/java/org/ethereum/beacon/consensus/transition/PerBlockTransition.java index e9bff4683..29e7e8479 100644 --- a/consensus/src/main/java/org/ethereum/beacon/consensus/transition/PerBlockTransition.java +++ b/consensus/src/main/java/org/ethereum/beacon/consensus/transition/PerBlockTransition.java @@ -13,7 +13,7 @@ * Per-block transition, which happens at every block. * * @see Per-block + * href="https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#per-block-processing">Per-block * processing in the spec. */ public class PerBlockTransition implements BlockTransition { @@ -29,8 +29,8 @@ public PerBlockTransition(BeaconChainSpec spec) { public BeaconStateEx apply(BeaconStateEx stateEx, BeaconBlock block) { logger.trace(() -> "Applying block transition to state: (" + spec.hash_tree_root(stateEx).toStringShort() + ") " - + stateEx.toString(spec.getConstants(), spec::signed_root) + ", Block: " - + block.toString(spec.getConstants(), stateEx.getGenesisTime(), spec::signed_root)); + + stateEx.toString(spec.getConstants(), spec::signing_root) + ", Block: " + + block.toString(spec.getConstants(), stateEx.getGenesisTime(), spec::signing_root)); TransitionType.BLOCK.checkCanBeAppliedAfter(stateEx.getTransition()); @@ -70,7 +70,7 @@ public BeaconStateEx apply(BeaconStateEx stateEx, BeaconBlock block) { logger.trace(() -> "Block transition result state: (" + spec.hash_tree_root(ret).toStringShort() + ") " + - ret.toString(spec.getConstants(), spec::signed_root)); + ret.toString(spec.getConstants(), spec::signing_root)); return ret; } diff --git a/consensus/src/main/java/org/ethereum/beacon/consensus/transition/PerEpochTransition.java b/consensus/src/main/java/org/ethereum/beacon/consensus/transition/PerEpochTransition.java index bf6de3ede..05017e4fc 100644 --- a/consensus/src/main/java/org/ethereum/beacon/consensus/transition/PerEpochTransition.java +++ b/consensus/src/main/java/org/ethereum/beacon/consensus/transition/PerEpochTransition.java @@ -1,5 +1,7 @@ package org.ethereum.beacon.consensus.transition; +import java.util.ArrayList; +import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; import org.apache.logging.log4j.LogManager; @@ -9,21 +11,22 @@ import org.ethereum.beacon.consensus.StateTransition; import org.ethereum.beacon.consensus.TransitionType; import org.ethereum.beacon.core.MutableBeaconState; +import org.ethereum.beacon.core.operations.attestation.Crosslink; import org.ethereum.beacon.core.state.PendingAttestation; -import org.ethereum.beacon.core.state.ShardCommittee; +import org.ethereum.beacon.core.state.ValidatorRecord; import org.ethereum.beacon.core.types.EpochNumber; import org.ethereum.beacon.core.types.Gwei; import org.ethereum.beacon.core.types.ShardNumber; -import org.ethereum.beacon.core.types.SlotNumber; import org.ethereum.beacon.core.types.ValidatorIndex; import org.javatuples.Pair; -import tech.pegasys.artemis.ethereum.core.Hash32; +import tech.pegasys.artemis.util.uint.UInt64; +import tech.pegasys.artemis.util.uint.UInt64s; /** * Per-epoch transition, which happens at the start of the first slot of every epoch. * * @see Per-epoch + * href="https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#per-epoch-processing">Per-epoch * processing in the spec. */ public class PerEpochTransition implements StateTransition { @@ -40,16 +43,10 @@ public BeaconStateEx apply(BeaconStateEx stateEx) { return apply(stateEx, null); } - public EpochTransitionSummary applyWithSummary(BeaconStateEx stateEx) { - EpochTransitionSummary summary = new EpochTransitionSummary(); - apply(stateEx, summary); - return summary; - } - BeaconStateEx apply(BeaconStateEx origState, EpochTransitionSummary summary) { logger.debug(() -> "Applying epoch transition to state: (" + spec.hash_tree_root(origState).toStringShort() + ") " + - origState.toString(spec.getConstants(), spec::signed_root)); + origState.toString(spec.getConstants(), spec::signing_root)); TransitionType.EPOCH.checkCanBeAppliedAfter(origState.getTransition()); @@ -61,18 +58,17 @@ BeaconStateEx apply(BeaconStateEx origState, EpochTransitionSummary summary) { if (summary != null) { summary.currentEpochSummary.activeAttesters = - spec.get_active_validator_indices( - state.getValidatorRegistry(), spec.get_current_epoch(state)); + spec.get_active_validator_indices(state, spec.get_current_epoch(state)); summary.currentEpochSummary.validatorBalance = spec.get_total_balance(state, summary.currentEpochSummary.activeAttesters); List current_epoch_boundary_attestations = - spec.get_current_epoch_boundary_attestations(state); + spec.get_matching_source_attestations(state, spec.get_current_epoch(state)); summary.currentEpochSummary.boundaryAttesters = current_epoch_boundary_attestations.stream() .flatMap( a -> spec - .get_attestation_participants( + .get_attesting_indices( state, a.getData(), a.getAggregationBitfield()) .stream()) .collect(Collectors.toList()); @@ -80,31 +76,30 @@ BeaconStateEx apply(BeaconStateEx origState, EpochTransitionSummary summary) { spec.get_attesting_balance(state, current_epoch_boundary_attestations); summary.previousEpochSummary.activeAttesters = - spec.get_active_validator_indices( - state.getValidatorRegistry(), spec.get_previous_epoch(state)); + spec.get_active_validator_indices(state, spec.get_previous_epoch(state)); summary.previousEpochSummary.validatorBalance = spec.get_total_balance(state, summary.previousEpochSummary.activeAttesters); List previous_epoch_boundary_attestations = - spec.get_previous_epoch_boundary_attestations(state); + spec.get_matching_source_attestations(state, spec.get_previous_epoch(state)); summary.previousEpochSummary.boundaryAttesters = previous_epoch_boundary_attestations.stream() .flatMap( a -> spec - .get_attestation_participants( + .get_attesting_indices( state, a.getData(), a.getAggregationBitfield()) .stream()) .collect(Collectors.toList()); summary.previousEpochSummary.boundaryAttestingBalance = spec.get_attesting_balance(state, previous_epoch_boundary_attestations); List previous_epoch_matching_head_attestations = - spec.get_previous_epoch_matching_head_attestations(state); + spec.get_matching_head_attestations(state, spec.get_previous_epoch(state)); summary.headAttesters = previous_epoch_matching_head_attestations.stream() .flatMap( a -> spec - .get_attestation_participants( + .get_attesting_indices( state, a.getData(), a.getAggregationBitfield()) .stream()) .collect(Collectors.toList()); @@ -114,137 +109,132 @@ BeaconStateEx apply(BeaconStateEx origState, EpochTransitionSummary summary) { EpochNumber epochs_since_finality = spec.get_current_epoch(state).increment().minus(state.getFinalizedEpoch()); - if (epochs_since_finality.lessEqual(EpochNumber.of(4))) { + if (epochs_since_finality.lessEqual(spec.getConstants().getMinEpochsToInactivityPenalty())) { summary.noFinality = false; + } else { + summary.noFinality = true; + } - // Some helper variables - List previous_epoch_attestations = - state.getPreviousEpochAttestations().listCopy(); - List boundary_attestations = spec.get_previous_epoch_boundary_attestations(state); - Gwei boundary_attesting_balance = spec.get_attesting_balance(state, boundary_attestations); - Gwei total_balance = spec.get_previous_total_balance(state); - Gwei total_attesting_balance = spec.get_attesting_balance(state, previous_epoch_attestations); - List matching_head_attestations = - spec.get_previous_epoch_matching_head_attestations(state); - Gwei matching_head_balance = spec.get_attesting_balance(state, matching_head_attestations); + EpochNumber previous_epoch = spec.get_previous_epoch(state); + Gwei total_balance = spec.get_total_active_balance(state); - // Process rewards or penalties for all validators - List active_validator_indices = - spec.get_active_validator_indices(state.getValidatorRegistry(), spec.get_previous_epoch(state)); + List eligible_validator_indices = new ArrayList<>(); + for (ValidatorIndex index : state.getValidatorRegistry().size()) { + ValidatorRecord validator = state.getValidatorRegistry().get(index); + if (spec.is_active_validator(validator, previous_epoch) + && (validator.getSlashed() && previous_epoch.increment().less(validator.getWithdrawableEpoch()))) { + eligible_validator_indices.add(index); + } + } - for (ValidatorIndex index : active_validator_indices) { - // Expected FFG source - if (spec.get_attesting_indices(state, previous_epoch_attestations).contains(index)) { + List matching_source_attestations = + spec.get_matching_source_attestations(state, previous_epoch); + List matching_target_attestations = + spec.get_matching_target_attestations(state, previous_epoch); + List matching_head_attestations = + spec.get_matching_head_attestations(state, previous_epoch); + + // attestation source rewards/penalties + { + List unslashed_attesting_indices = + spec.get_unslashed_attesting_indices(state, matching_source_attestations); + Gwei attesting_balance = spec.get_attesting_balance(state, matching_source_attestations); + for (ValidatorIndex index : eligible_validator_indices) { + if (unslashed_attesting_indices.contains(index)) { summary.attestationRewards.put(index, - spec.get_base_reward(state, index).mulDiv(total_attesting_balance, total_balance)); - // Inclusion speed bonus - summary.inclusionDistanceRewards.put(index, - spec.get_base_reward(state, index) - .mulDiv(Gwei.castFrom(spec.getConstants().getMinAttestationInclusionDelay()), - Gwei.castFrom(spec.inclusion_distance(state, index)))); + spec.get_base_reward(state, index).times(attesting_balance).dividedBy(total_balance)); } else { summary.attestationPenalties.put(index, spec.get_base_reward(state, index)); } + } + } - // Expected FFG target - if (spec.get_attesting_indices(state, boundary_attestations).contains(index)) { + // attestation target rewards/penalties + { + List unslashed_attesting_indices = + spec.get_unslashed_attesting_indices(state, matching_target_attestations); + Gwei attesting_balance = spec.get_attesting_balance(state, matching_target_attestations); + for (ValidatorIndex index : eligible_validator_indices) { + if (unslashed_attesting_indices.contains(index)) { summary.boundaryAttestationRewards.put(index, - spec.get_base_reward(state, index).mulDiv(boundary_attesting_balance, total_balance)); + spec.get_base_reward(state, index).times(attesting_balance).dividedBy(total_balance)); } else { summary.boundaryAttestationPenalties.put(index, spec.get_base_reward(state, index)); } - - // Expected head - if (spec.get_attesting_indices(state, matching_head_attestations).contains(index)) { - summary.beaconHeadAttestationRewards.put(index, - spec.get_base_reward(state, index).mulDiv(matching_head_balance, total_balance)); - } else { - summary.beaconHeadAttestationPenalties.put(index, - spec.get_base_reward(state, index)); - } } + } - } else { - summary.noFinality = true; - - List previous_epoch_attestations = - state.getPreviousEpochAttestations().listCopy(); - List boundary_attestations = - spec.get_previous_epoch_boundary_attestations(state); - List matching_head_attestations = - spec.get_previous_epoch_matching_head_attestations(state); - List active_validator_indices = - spec.get_active_validator_indices(state.getValidatorRegistry(), spec.get_previous_epoch(state)); - - // for index in active_validator_indices: - for (ValidatorIndex index : active_validator_indices) { - if (!spec.get_attesting_indices(state, previous_epoch_attestations).contains(index)) { - summary.attestationPenalties.put(index, - spec.get_inactivity_penalty(state, index, epochs_since_finality)); + // chain head rewards/penalties + { + List unslashed_attesting_indices = + spec.get_unslashed_attesting_indices(state, matching_head_attestations); + Gwei attesting_balance = spec.get_attesting_balance(state, matching_head_attestations); + for (ValidatorIndex index : eligible_validator_indices) { + if (unslashed_attesting_indices.contains(index)) { + summary.beaconHeadAttestationRewards.put(index, + spec.get_base_reward(state, index).times(attesting_balance).dividedBy(total_balance)); } else { - // If a validator did attest, apply a small penalty for getting attestations included late - summary.noFinalityPenalties.put(index, spec.get_base_reward(state, index).mulDiv( - Gwei.castFrom(spec.getConstants().getMinAttestationInclusionDelay()), - Gwei.castFrom(spec.inclusion_distance(state, index)))); - } - - if (!spec.get_attesting_indices(state, boundary_attestations).contains(index)) { - summary.boundaryAttestationPenalties.put(index, - spec.get_inactivity_penalty(state, index, epochs_since_finality)); - } - if (!spec.get_attesting_indices(state, matching_head_attestations).contains(index)) { summary.beaconHeadAttestationPenalties.put(index, spec.get_base_reward(state, index)); } } + } - // Penalize slashed-but-inactive validators as though they were active but offline - for (ValidatorIndex index : state.getValidatorRegistry().size()) { - boolean eligible = !active_validator_indices.contains(index) && - state.getValidatorRegistry().get(index).getSlashed() && - spec.get_current_epoch(state).less(state.getValidatorRegistry().get(index).getWithdrawableEpoch()); + // inclusion rewards + for (ValidatorIndex index : spec.get_unslashed_attesting_indices(state, matching_source_attestations)) { + PendingAttestation attestation = + matching_source_attestations.stream() + .filter(a -> spec.get_attesting_indices(state, a.getData(), a.getAggregationBitfield()).contains(index)) + .min(Comparator.comparing(PendingAttestation::getInclusionDelay)) + .get(); + summary.inclusionDistanceRewards.put(index, + spec.get_base_reward(state, index) + .times(spec.getConstants().getMinAttestationInclusionDelay()) + .dividedBy(attestation.getInclusionDelay())); + } - if (eligible) { + // inactivity penalty + EpochNumber finality_delay = previous_epoch.minus(state.getFinalizedEpoch()); + if (finality_delay.greater(spec.getConstants().getMinEpochsToInactivityPenalty())) { + List matching_target_attesting_indices = + spec.get_unslashed_attesting_indices(state, matching_target_attestations); + for (ValidatorIndex index : eligible_validator_indices) { + summary.noFinalityPenalties.put(index, + spec.get_base_reward(state, index).times(spec.getConstants().getBaseRewardsPerEpoch())); + if (!matching_target_attesting_indices.contains(index)) { summary.initiatedExitPenalties.put(index, - spec.get_inactivity_penalty(state, index, epochs_since_finality).times(2) - .plus(spec.get_base_reward(state, index))); + state.getValidatorRegistry().get(index).getEffectiveBalance() + .times(finality_delay) + .dividedBy(spec.getConstants().getInactivityPenaltyQuotient())); } } } - - SlotNumber previous_epoch_start_slot = spec.get_epoch_start_slot(spec.get_previous_epoch(state)); - SlotNumber current_epoch_start_slot = spec.get_epoch_start_slot(spec.get_current_epoch(state)); - for (SlotNumber slot : previous_epoch_start_slot.iterateTo(current_epoch_start_slot)) { - List committees_and_shards = spec.get_crosslink_committees_at_slot(state, slot); - for (ShardCommittee committee_and_shard : committees_and_shards) { - List crosslink_committee = committee_and_shard.getCommittee(); - ShardNumber shard = committee_and_shard.getShard(); - Pair> winning_root_and_participants = - spec.get_winning_root_and_participants(state, slot, shard); - Gwei participating_balance = spec.get_total_balance(state, winning_root_and_participants.getValue1()); - Gwei total_balance = spec.get_total_balance(state, crosslink_committee); - - for (ValidatorIndex index : crosslink_committee) { - if (winning_root_and_participants.getValue1().contains(index)) { - summary.attestationInclusionRewards.put(index, - spec.get_base_reward(state, index).mulDiv(participating_balance, total_balance)); - } + EpochNumber epoch = previous_epoch; + for (UInt64 offset : UInt64s.iterate(UInt64.ZERO, spec.get_epoch_committee_count(state, epoch))) { + ShardNumber shard = spec.get_epoch_start_shard(state, epoch) + .plusModulo(offset, spec.getConstants().getShardCount()); + List crosslink_committee = spec.get_crosslink_committee(state, epoch, shard); + Pair> winner = + spec.get_winning_crosslink_and_attesting_indices(state, epoch, shard); + List attesting_indices = winner.getValue1(); + Gwei attesting_balance = spec.get_total_balance(state, attesting_indices); + Gwei committee_balance = spec.get_total_balance(state, crosslink_committee); + for (ValidatorIndex index : crosslink_committee) { + Gwei base_reward = spec.get_base_reward(state, index); + if (attesting_indices.contains(index)) { + summary.attestationInclusionRewards.put(index, + base_reward.times(attesting_balance).dividedBy(committee_balance)); } } } - - } - spec.update_justification_and_finalization(state); + spec.process_justification_and_finalization(state); spec.process_crosslinks(state); - spec.maybe_reset_eth1_period(state); - spec.apply_rewards(state); - List ejectedValidators = spec.process_ejections(state); - spec.update_registry_and_shuffling_data(state); + spec.process_rewards_and_penalties(state); + List ejectedValidators = spec.process_registry_updates(state); spec.process_slashings(state); - spec.process_exit_queue(state); - spec.finish_epoch_update(state); + spec.process_final_updates(state); BeaconStateEx ret = new BeaconStateExImpl(state.createImmutable(), TransitionType.EPOCH); @@ -255,7 +245,7 @@ BeaconStateEx apply(BeaconStateEx origState, EpochTransitionSummary summary) { logger.debug(() -> "Epoch transition result state: (" + spec.hash_tree_root(ret).toStringShort() + ") " + - ret.toString(spec.getConstants(), spec::signed_root)); + ret.toString(spec.getConstants(), spec::signing_root)); return ret; } diff --git a/consensus/src/main/java/org/ethereum/beacon/consensus/transition/PerSlotTransition.java b/consensus/src/main/java/org/ethereum/beacon/consensus/transition/PerSlotTransition.java index 2c58d8fdb..24fa1c798 100644 --- a/consensus/src/main/java/org/ethereum/beacon/consensus/transition/PerSlotTransition.java +++ b/consensus/src/main/java/org/ethereum/beacon/consensus/transition/PerSlotTransition.java @@ -12,7 +12,7 @@ * Per-slot transition, which happens at every slot. * * @see Per-slot + * href="https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#per-slot-processing">Per-slot * processing in the spec. */ public class PerSlotTransition implements StateTransition { @@ -28,7 +28,7 @@ public PerSlotTransition(BeaconChainSpec spec) { public BeaconStateEx apply(BeaconStateEx stateEx) { logger.trace(() -> "Applying slot transition to state: (" + spec.hash_tree_root(stateEx).toStringShort() + ") " + - stateEx.toString(spec.getConstants(), spec::signed_root)); + stateEx.toString(spec.getConstants(), spec::signing_root)); TransitionType.SLOT.checkCanBeAppliedAfter(stateEx.getTransition()); MutableBeaconState state = stateEx.createMutableCopy(); @@ -39,7 +39,7 @@ public BeaconStateEx apply(BeaconStateEx stateEx) { logger.trace(() -> "Slot transition result state: (" + spec.hash_tree_root(ret).toStringShort() + ") " + - ret.toString(spec.getConstants(), spec::signed_root)); + ret.toString(spec.getConstants(), spec::signing_root)); return ret; } diff --git a/consensus/src/main/java/org/ethereum/beacon/consensus/transition/StateCachingTransition.java b/consensus/src/main/java/org/ethereum/beacon/consensus/transition/StateCachingTransition.java index 4a7afa07e..0537bb153 100644 --- a/consensus/src/main/java/org/ethereum/beacon/consensus/transition/StateCachingTransition.java +++ b/consensus/src/main/java/org/ethereum/beacon/consensus/transition/StateCachingTransition.java @@ -12,7 +12,7 @@ * State caching, which happens at the start of every slot. * * @see State + * href="https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#state-caching">State * caching in the spec. */ public class StateCachingTransition implements StateTransition { @@ -28,7 +28,7 @@ public StateCachingTransition(BeaconChainSpec spec) { public BeaconStateEx apply(BeaconStateEx source) { logger.debug(() -> "Applying state caching to state: (" + spec.hash_tree_root(source).toStringShort() + ") " + - source.toString(spec.getConstants(), spec::signed_root)); + source.toString(spec.getConstants(), spec::signing_root)); TransitionType.CACHING.checkCanBeAppliedAfter(source.getTransition()); @@ -40,7 +40,7 @@ public BeaconStateEx apply(BeaconStateEx source) { logger.debug(() -> "State caching result state: (" + spec.hash_tree_root(ret).toStringShort() + ") " + - ret.toString(spec.getConstants(), spec::signed_root)); + ret.toString(spec.getConstants(), spec::signing_root)); return ret; } diff --git a/consensus/src/main/java/org/ethereum/beacon/consensus/util/CachingBeaconChainSpec.java b/consensus/src/main/java/org/ethereum/beacon/consensus/util/CachingBeaconChainSpec.java index 2f07d52d3..e5107c738 100644 --- a/consensus/src/main/java/org/ethereum/beacon/consensus/util/CachingBeaconChainSpec.java +++ b/consensus/src/main/java/org/ethereum/beacon/consensus/util/CachingBeaconChainSpec.java @@ -8,12 +8,9 @@ import org.ethereum.beacon.consensus.hasher.ObjectHasher; import org.ethereum.beacon.core.BeaconState; import org.ethereum.beacon.core.spec.SpecConstants; -import org.ethereum.beacon.core.state.ShardCommittee; -import org.ethereum.beacon.core.state.ValidatorRecord; import org.ethereum.beacon.core.types.BLSPubkey; import org.ethereum.beacon.core.types.EpochNumber; -import org.ethereum.beacon.core.types.Gwei; -import org.ethereum.beacon.core.types.SlotNumber; +import org.ethereum.beacon.core.types.ShardNumber; import org.ethereum.beacon.core.types.ValidatorIndex; import org.ethereum.beacon.util.cache.Cache; import org.ethereum.beacon.util.cache.CacheFactory; @@ -21,7 +18,6 @@ import tech.pegasys.artemis.ethereum.core.Hash32; import tech.pegasys.artemis.util.bytes.Bytes32; import tech.pegasys.artemis.util.bytes.BytesValue; -import tech.pegasys.artemis.util.collections.ReadList; import tech.pegasys.artemis.util.uint.UInt64; public class CachingBeaconChainSpec extends BeaconChainSpecImpl { @@ -29,9 +25,8 @@ public class CachingBeaconChainSpec extends BeaconChainSpecImpl { private final Cache, Bytes32>, List> shufflerCache; private final Cache hashTreeRootCache; private final Cache signedRootCache; - private final Cache> crosslinkCommitteesCache; + private final Cache, List> crosslinkCommitteesCache; private final Cache> activeValidatorsCache; - private final Cache totalBalanceCache; private ValidatorIndex maxCachedIndex = ValidatorIndex.ZERO; private final Map pubkeyToIndexCache = new ConcurrentHashMap<>(); @@ -54,7 +49,6 @@ public CachingBeaconChainSpec( this.signedRootCache = factory.createLRUCache(1024); this.crosslinkCommitteesCache = factory.createLRUCache(128); this.activeValidatorsCache = factory.createLRUCache(32); - this.totalBalanceCache = factory.createLRUCache(32); } public CachingBeaconChainSpec( @@ -79,8 +73,8 @@ public Hash32 hash_tree_root(Object object) { } @Override - public Hash32 signed_root(Object object) { - return signedRootCache.get(object, super::signed_root); + public Hash32 signing_root(Object object) { + return signedRootCache.get(object, super::signing_root); } @Override @@ -100,23 +94,14 @@ public ValidatorIndex get_validator_index_by_pubkey(BeaconState state, BLSPubkey } @Override - public List get_crosslink_committees_at_slot( - BeaconState state, SlotNumber slot, boolean registry_change) { - return crosslinkCommitteesCache.get( - slot, s -> super.get_crosslink_committees_at_slot(state, slot, registry_change)); + public List get_crosslink_committee(BeaconState state, EpochNumber epoch, ShardNumber shard) { + return crosslinkCommitteesCache.get(Pair.with(epoch, shard), + s -> super.get_crosslink_committee(state, epoch, shard)); } @Override - public List get_active_validator_indices( - ReadList validators, EpochNumber epochNumber) { - return activeValidatorsCache.get( - epochNumber, e -> super.get_active_validator_indices(validators, epochNumber)); - } - - @Override - public Gwei get_previous_total_balance(BeaconState state) { - return totalBalanceCache.get( - get_previous_epoch(state), e -> super.get_previous_total_balance(state)); + public List get_active_validator_indices(BeaconState state, EpochNumber epoch) { + return activeValidatorsCache.get(epoch, e -> super.get_active_validator_indices(state, epoch)); } public boolean isCacheEnabled() { diff --git a/consensus/src/main/java/org/ethereum/beacon/consensus/verifier/BeaconBlockVerifier.java b/consensus/src/main/java/org/ethereum/beacon/consensus/verifier/BeaconBlockVerifier.java index a33edc0eb..b74df77b5 100644 --- a/consensus/src/main/java/org/ethereum/beacon/consensus/verifier/BeaconBlockVerifier.java +++ b/consensus/src/main/java/org/ethereum/beacon/consensus/verifier/BeaconBlockVerifier.java @@ -2,13 +2,15 @@ import org.ethereum.beacon.consensus.BeaconChainSpec; import org.ethereum.beacon.consensus.verifier.block.AttestationListVerifier; +import org.ethereum.beacon.consensus.verifier.block.AttesterSlashingListVerifier; import org.ethereum.beacon.consensus.verifier.block.DepositListVerifier; import org.ethereum.beacon.consensus.verifier.block.TransferListVerifier; import org.ethereum.beacon.consensus.verifier.block.VoluntaryExitListVerifier; -import org.ethereum.beacon.consensus.verifier.block.BlockSignatureVerifier; +import org.ethereum.beacon.consensus.verifier.block.BlockHeaderVerifier; import org.ethereum.beacon.consensus.verifier.block.ProposerSlashingListVerifier; import org.ethereum.beacon.consensus.verifier.block.RandaoVerifier; import org.ethereum.beacon.consensus.verifier.operation.AttestationVerifier; +import org.ethereum.beacon.consensus.verifier.operation.AttesterSlashingVerifier; import org.ethereum.beacon.consensus.verifier.operation.DepositVerifier; import org.ethereum.beacon.consensus.verifier.operation.TransferVerifier; import org.ethereum.beacon.consensus.verifier.operation.VoluntaryExitVerifier; @@ -22,11 +24,12 @@ public interface BeaconBlockVerifier { static BeaconBlockVerifier createDefault(BeaconChainSpec spec) { return CompositeBlockVerifier.Builder.createNew() .with(new RandaoVerifier(spec)) - .with(new BlockSignatureVerifier(spec)) + .with(new BlockHeaderVerifier(spec)) + .with(new ProposerSlashingListVerifier(new ProposerSlashingVerifier(spec), spec.getConstants())) + .with(new AttesterSlashingListVerifier(new AttesterSlashingVerifier(spec), spec.getConstants())) .with(new AttestationListVerifier(new AttestationVerifier(spec), spec.getConstants())) .with(new DepositListVerifier(new DepositVerifier(spec), spec.getConstants())) .with(new VoluntaryExitListVerifier(new VoluntaryExitVerifier(spec), spec.getConstants())) - .with(new ProposerSlashingListVerifier(new ProposerSlashingVerifier(spec), spec.getConstants())) .with(new TransferListVerifier(new TransferVerifier(spec), spec)) .build(); } diff --git a/consensus/src/main/java/org/ethereum/beacon/consensus/verifier/block/AttesterSlashingListVerifier.java b/consensus/src/main/java/org/ethereum/beacon/consensus/verifier/block/AttesterSlashingListVerifier.java new file mode 100644 index 000000000..556cc2a7f --- /dev/null +++ b/consensus/src/main/java/org/ethereum/beacon/consensus/verifier/block/AttesterSlashingListVerifier.java @@ -0,0 +1,26 @@ +package org.ethereum.beacon.consensus.verifier.block; + +import org.ethereum.beacon.consensus.verifier.OperationVerifier; +import org.ethereum.beacon.core.operations.slashing.AttesterSlashing; +import org.ethereum.beacon.core.spec.SpecConstants; + +/** + * Verifies attester slashing list. + * + * @see AttesterSlashing + */ +public class AttesterSlashingListVerifier extends OperationListVerifier { + + public AttesterSlashingListVerifier( + OperationVerifier operationVerifier, SpecConstants specConstants) { + super( + operationVerifier, + block -> block.getBody().getAttesterSlashings(), + specConstants.getMaxAttesterSlashings()); + } + + @Override + protected Class getType() { + return AttesterSlashing.class; + } +} diff --git a/consensus/src/main/java/org/ethereum/beacon/consensus/verifier/block/BlockHeaderVerifier.java b/consensus/src/main/java/org/ethereum/beacon/consensus/verifier/block/BlockHeaderVerifier.java new file mode 100644 index 000000000..9e422c225 --- /dev/null +++ b/consensus/src/main/java/org/ethereum/beacon/consensus/verifier/block/BlockHeaderVerifier.java @@ -0,0 +1,34 @@ +package org.ethereum.beacon.consensus.verifier.block; + +import org.ethereum.beacon.consensus.BeaconChainSpec; +import org.ethereum.beacon.consensus.verifier.BeaconBlockVerifier; +import org.ethereum.beacon.consensus.verifier.VerificationResult; +import org.ethereum.beacon.core.BeaconBlock; +import org.ethereum.beacon.core.BeaconState; + +/** + * Verifies block header. + * + * @see Block + * header in the spec. + */ +public class BlockHeaderVerifier implements BeaconBlockVerifier { + + private BeaconChainSpec spec; + + public BlockHeaderVerifier(BeaconChainSpec spec) { + this.spec = spec; + } + + @Override + public VerificationResult verify(BeaconBlock block, BeaconState state) { + try { + spec.verify_block_header(state, block); + return VerificationResult.PASSED; + } catch (Exception e) { + return VerificationResult.failedResult( + "Block header verification has failed: %s", e.getMessage()); + } + } +} diff --git a/consensus/src/main/java/org/ethereum/beacon/consensus/verifier/block/BlockSignatureVerifier.java b/consensus/src/main/java/org/ethereum/beacon/consensus/verifier/block/BlockSignatureVerifier.java deleted file mode 100644 index d333b52c5..000000000 --- a/consensus/src/main/java/org/ethereum/beacon/consensus/verifier/block/BlockSignatureVerifier.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.ethereum.beacon.consensus.verifier.block; - -import org.ethereum.beacon.consensus.BeaconChainSpec; -import org.ethereum.beacon.consensus.verifier.BeaconBlockVerifier; -import org.ethereum.beacon.consensus.verifier.VerificationResult; -import org.ethereum.beacon.core.BeaconBlock; -import org.ethereum.beacon.core.BeaconState; -import org.ethereum.beacon.core.types.BLSPubkey; -import org.ethereum.beacon.core.types.ValidatorIndex; -import tech.pegasys.artemis.ethereum.core.Hash32; -import tech.pegasys.artemis.util.uint.UInt64; - -import static org.ethereum.beacon.core.spec.SignatureDomains.BEACON_BLOCK; - -/** - * Verifies proposer signature of the block. - * - * @see Block - * signature in the spec. - */ -public class BlockSignatureVerifier implements BeaconBlockVerifier { - - private BeaconChainSpec spec; - - public BlockSignatureVerifier(BeaconChainSpec spec) { - this.spec = spec; - } - - @Override - public VerificationResult verify(BeaconBlock block, BeaconState state) { - Hash32 headerRoot = spec.signed_root(block); - - // Verify that bls_verify( - // pubkey=state.validator_registry[get_beacon_proposer_index(state, state.slot)].pubkey, - // message=proposal_root, - // signature=block.signature, - // domain=get_domain(state.fork, get_current_epoch(state), DOMAIN_PROPOSAL)). - ValidatorIndex proposerIndex = spec.get_beacon_proposer_index(state, state.getSlot()); - BLSPubkey publicKey = state.getValidatorRegistry().get(proposerIndex).getPubKey(); - UInt64 domain = - spec.get_domain(state.getFork(), spec.get_current_epoch(state), BEACON_BLOCK); - - if (spec.bls_verify(publicKey, headerRoot, block.getSignature(), domain)) { - return VerificationResult.PASSED; - } else { - return VerificationResult.failedResult( - "Proposer signature verification has failed for block %s", block); - } - } -} diff --git a/consensus/src/main/java/org/ethereum/beacon/consensus/verifier/block/RandaoVerifier.java b/consensus/src/main/java/org/ethereum/beacon/consensus/verifier/block/RandaoVerifier.java index 9940d1ba3..4931ccb0c 100644 --- a/consensus/src/main/java/org/ethereum/beacon/consensus/verifier/block/RandaoVerifier.java +++ b/consensus/src/main/java/org/ethereum/beacon/consensus/verifier/block/RandaoVerifier.java @@ -13,7 +13,7 @@ * Verifies RANDAO reveal. * * @see RANDAO + * href="https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#randao">RANDAO * in the spec. */ public class RandaoVerifier implements BeaconBlockVerifier { @@ -26,27 +26,12 @@ public RandaoVerifier(BeaconChainSpec spec) { @Override public VerificationResult verify(BeaconBlock block, BeaconState state) { - // Let proposer = state.validator_registry[get_beacon_proposer_index(state, state.slot)]. - ValidatorRecord proposer = - state - .getValidatorRegistry() - .get(spec.get_beacon_proposer_index(state, state.getSlot())); - - /* assert bls_verify( - pubkey=proposer.pubkey, - message_hash=hash_tree_root(get_current_epoch(state)), - signature=block.body.randao_reveal, - domain=get_domain(state.fork, get_current_epoch(state), DOMAIN_RANDAO) - ) */ - if (!spec.bls_verify( - proposer.getPubKey(), - spec.hash_tree_root(spec.get_current_epoch(state)), - block.getBody().getRandaoReveal(), - spec.get_domain(state.getFork(), spec.get_current_epoch(state), RANDAO))) { - - return VerificationResult.failedResult("RANDAO reveal verification failed"); + try { + spec.verify_randao(state, block); + return VerificationResult.PASSED; + } catch (Exception e) { + return VerificationResult.failedResult( + "RANDAO reveal verification failed: %s", e.getMessage()); } - - return VerificationResult.PASSED; } } diff --git a/consensus/src/main/java/org/ethereum/beacon/consensus/verifier/operation/AttestationVerifier.java b/consensus/src/main/java/org/ethereum/beacon/consensus/verifier/operation/AttestationVerifier.java index f94fb5295..d8954169f 100644 --- a/consensus/src/main/java/org/ethereum/beacon/consensus/verifier/operation/AttestationVerifier.java +++ b/consensus/src/main/java/org/ethereum/beacon/consensus/verifier/operation/AttestationVerifier.java @@ -1,35 +1,17 @@ package org.ethereum.beacon.consensus.verifier.operation; -import static org.ethereum.beacon.consensus.verifier.VerificationResult.PASSED; -import static org.ethereum.beacon.consensus.verifier.VerificationResult.failedResult; -import static org.ethereum.beacon.core.spec.SignatureDomains.ATTESTATION; - -import java.util.Arrays; -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; import org.ethereum.beacon.consensus.BeaconChainSpec; import org.ethereum.beacon.consensus.verifier.OperationVerifier; import org.ethereum.beacon.consensus.verifier.VerificationResult; import org.ethereum.beacon.core.BeaconState; import org.ethereum.beacon.core.operations.Attestation; -import org.ethereum.beacon.core.operations.attestation.AttestationData; -import org.ethereum.beacon.core.operations.attestation.AttestationDataAndCustodyBit; -import org.ethereum.beacon.core.operations.attestation.Crosslink; -import org.ethereum.beacon.core.state.ShardCommittee; -import org.ethereum.beacon.core.types.BLSPubkey; -import org.ethereum.beacon.core.types.ShardNumber; -import org.ethereum.beacon.core.types.ValidatorIndex; -import org.ethereum.beacon.crypto.BLS381.PublicKey; -import tech.pegasys.artemis.ethereum.core.Hash32; -import tech.pegasys.artemis.util.collections.ReadList; /** * Verifies {@link Attestation} beacon chain operation. * * @see Attestation * @see Attesations + * href="https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#attestations">Attesations * in the spec. */ public class AttestationVerifier implements OperationVerifier { @@ -42,156 +24,11 @@ public AttestationVerifier(BeaconChainSpec spec) { @Override public VerificationResult verify(Attestation attestation, BeaconState state) { - AttestationData data = attestation.getData(); - - if (attestation.getData().getSlot().less(spec.getConstants().getGenesisSlot())) { - return failedResult("Attestation slot %s is less than GENESIS_SLOT %s", - attestation.getData().getSlot(), spec.getConstants().getGenesisSlot()); - } - - spec.checkShardRange(data.getShard()); - - // Verify that attestation.data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot - // < attestation.data.slot + SLOTS_PER_EPOCH - if (state.getSlot() - .less(data.getSlot().plus(spec.getConstants().getMinAttestationInclusionDelay()))) { - return failedResult( - "MIN_ATTESTATION_INCLUSION_DELAY violated, inclusion slot starts from %s but got %s", - data.getSlot().plus(spec.getConstants().getMinAttestationInclusionDelay()), state.getSlot()); - } - if (state.getSlot().greaterEqual(data.getSlot().plus(spec.getConstants().getSlotsPerEpoch()))) { - return failedResult( - "MIN_ATTESTATION_INCLUSION_DELAY violated, inclusion slot limit is %s but got %s", - data.getSlot().plus(spec.getConstants().getSlotsPerEpoch()).decrement(), - state.getSlot()); - } - - // # Can't submit attestations too quickly - // assert attestation.data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot - if (!data.getSlot().plus(spec.getConstants().getMinAttestationInclusionDelay()) - .lessEqual(state.getSlot())) { - return failedResult( - "attestation inclusion upper limit violated, inclusion slot ends with %s but got %s", - state.getSlot(), - data.getSlot().plus(spec.getConstants().getMinAttestationInclusionDelay())); - } - - /* # Verify that the justified epoch and root is correct - if slot_to_epoch(attestation.data.slot) >= get_current_epoch(state): - # Case 1: current epoch attestations - assert attestation.data.source_epoch == state.current_justified_epoch - assert attestation.data.source_root == state.current_justified_root - else: - # Case 2: previous epoch attestations - assert attestation.data.source_epoch == state.previous_justified_epoch - assert attestation.data.source_root == state.previous_justified_root */ - - if (spec.slot_to_epoch(data.getSlot()).greaterEqual(spec.get_current_epoch(state))) { - if (!(data.getSourceEpoch().equals(state.getCurrentJustifiedEpoch()))) { - return failedResult("case 1: source_epoch doesn't match, expected %s but got %s", - state.getCurrentJustifiedEpoch(), data.getSourceEpoch()); - } - if (!(data.getSourceRoot().equals(state.getCurrentJustifiedRoot()))) { - return failedResult("case 1: source_root doesn't match, expected %s but got %s", - state.getCurrentJustifiedRoot(), data.getSourceRoot()); - } - } else { - if (!(data.getSourceEpoch().equals(state.getPreviousJustifiedEpoch()))) { - return failedResult("case 2: source_epoch doesn't match, expected %s but got %s", - state.getPreviousJustifiedEpoch(), data.getSourceEpoch()); - } - if (!(data.getSourceRoot().equals(state.getPreviousJustifiedRoot()))) { - return failedResult("case 2: source_root doesn't match, expected %s but got %s", - state.getPreviousJustifiedRoot(), data.getSourceRoot()); - } + try { + spec.verify_attestation(state, attestation); + return VerificationResult.PASSED; + } catch (Exception e) { + return VerificationResult.failedResult(e.getMessage()); } - - // Check crosslink data - /* assert attestation.data.crosslink_data_root == ZERO_HASH # [to be removed in phase 1] - crosslinks = state.current_crosslinks if slot_to_epoch(attestation.data.slot) == get_current_epoch(state) else state.previous_crosslinks - assert crosslinks[attestation.data.shard] == attestation.data.previous_crosslink */ - ReadList crosslinks = - spec.slot_to_epoch(data.getSlot()).equals(spec.get_current_epoch(state)) ? - state.getCurrentCrosslinks() : state.getPreviousCrosslinks(); - if (!crosslinks.get(data.getShard()).equals(data.getPreviousCrosslink())) { - return failedResult("attestation.data.latest_crosslink is incorrect"); - } - - if (!Hash32.ZERO.equals(data.getCrosslinkDataRoot())) { - return failedResult( - "attestation_data.crosslink_data_root must be equal to zero hash, phase 0 check"); - } - - // assert attestation.custody_bitfield == b'\x00' * len(attestation.custody_bitfield) # [TO BE REMOVED IN PHASE 1] - if (!attestation.getCustodyBitfield().isZero()) { - return failedResult("attestation.custody_bitfield != ZERO"); - } - // assert attestation.aggregation_bitfield != b'\x00' * len(attestation.aggregation_bitfield) - if (attestation.getAggregationBitfield().isZero()) { - return failedResult("attestation.aggregation_bitfield == ZERO"); - } - - // crosslink_committee = [ - // committee for committee, shard in get_crosslink_committees_at_slot(state, attestation.data.slot) - // if shard == attestation.data.shard - // ][0] - Optional crosslink_committee_opt = spec - .get_crosslink_committees_at_slot(state, data.getSlot()).stream() - .filter(c -> c.getShard().equals(data.getShard())) - .findFirst(); - if (!crosslink_committee_opt.isPresent()) { - return failedResult("crosslink_committee not found"); - } - List crosslink_committee = crosslink_committee_opt.get().getCommittee(); - - // for i in range(len(crosslink_committee)): - // if get_bitfield_bit(attestation.aggregation_bitfield, i) == 0b0: - // assert get_bitfield_bit(attestation.custody_bitfield, i) == 0b0 - for (int i = 0; i < crosslink_committee.size(); i++) { - if (attestation.getAggregationBitfield().getBit(i) == false) { - if (attestation.getCustodyBitfield().getBit(i) != false) { - return failedResult("aggregation_bitfield and custody_bitfield doesn't match"); - } - } - } - - // participants = get_attestation_participants(state, attestation.data, attestation.aggregation_bitfield) - List participants = - spec.get_attestation_participants(state, data, attestation.getAggregationBitfield()); - - // custody_bit_1_participants = get_attestation_participants(state, attestation.data, attestation.custody_bitfield) - List custody_bit_1_participants = - spec.get_attestation_participants(state, data, attestation.getCustodyBitfield()); - // custody_bit_0_participants = [i in participants for i not in custody_bit_1_participants] - List custody_bit_0_participants = participants.stream() - .filter(i -> !custody_bit_1_participants.contains(i)).collect(Collectors.toList()); - - // assert bls_verify_multiple( - // pubkeys=[ - // bls_aggregate_pubkeys([state.validator_registry[i].pubkey for i in custody_bit_0_participants]), - // bls_aggregate_pubkeys([state.validator_registry[i].pubkey for i in custody_bit_1_participants]), - // ], - // messages=[ - // hash_tree_root(AttestationDataAndCustodyBit(data=attestation.data, custody_bit=0b0)), - // hash_tree_root(AttestationDataAndCustodyBit(data=attestation.data, custody_bit=0b1)), - // ], - // signature=attestation.aggregate_signature, - // domain=get_domain(state.fork, slot_to_epoch(attestation.data.slot), DOMAIN_ATTESTATION), - // ) - List pubKeys1 = spec.mapIndicesToPubKeys(state, custody_bit_0_participants); - PublicKey groupPublicKey1 = spec.bls_aggregate_pubkeys(pubKeys1); - List pubKeys2 = spec.mapIndicesToPubKeys(state, custody_bit_1_participants); - PublicKey groupPublicKey2 = spec.bls_aggregate_pubkeys(pubKeys2); - if (!spec.bls_verify_multiple( - Arrays.asList(groupPublicKey1, groupPublicKey2), - Arrays.asList( - spec.hash_tree_root(new AttestationDataAndCustodyBit(data, false)), - spec.hash_tree_root(new AttestationDataAndCustodyBit(data, true))), - attestation.getAggregateSignature(), - spec.get_domain(state.getFork(), spec.slot_to_epoch(data.getSlot()), ATTESTATION))) { - return failedResult("failed to verify aggregated signature"); - } - - return PASSED; } } diff --git a/consensus/src/main/java/org/ethereum/beacon/consensus/verifier/operation/AttesterSlashingVerifier.java b/consensus/src/main/java/org/ethereum/beacon/consensus/verifier/operation/AttesterSlashingVerifier.java index 197de786c..65b89e545 100644 --- a/consensus/src/main/java/org/ethereum/beacon/consensus/verifier/operation/AttesterSlashingVerifier.java +++ b/consensus/src/main/java/org/ethereum/beacon/consensus/verifier/operation/AttesterSlashingVerifier.java @@ -1,23 +1,17 @@ package org.ethereum.beacon.consensus.verifier.operation; -import static org.ethereum.beacon.consensus.verifier.VerificationResult.PASSED; -import static org.ethereum.beacon.consensus.verifier.VerificationResult.failedResult; - import org.ethereum.beacon.consensus.BeaconChainSpec; import org.ethereum.beacon.consensus.verifier.OperationVerifier; import org.ethereum.beacon.consensus.verifier.VerificationResult; import org.ethereum.beacon.core.BeaconState; import org.ethereum.beacon.core.operations.slashing.AttesterSlashing; -import org.ethereum.beacon.core.operations.slashing.SlashableAttestation; -import org.ethereum.beacon.core.types.ValidatorIndex; -import tech.pegasys.artemis.util.collections.ReadList; /** * Verifies {@link AttesterSlashing} beacon chain operation. * * @see AttesterSlashing * @see + * href="https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#attester-slashings"> * Attester slashings in the spec. */ public class AttesterSlashingVerifier implements OperationVerifier { @@ -30,40 +24,11 @@ public AttesterSlashingVerifier(BeaconChainSpec spec) { @Override public VerificationResult verify(AttesterSlashing attesterSlashing, BeaconState state) { - SlashableAttestation slashableAttestation1 = attesterSlashing.getSlashableAttestation1(); - SlashableAttestation slashableAttestation2 = attesterSlashing.getSlashableAttestation2(); - - spec.checkIndexRange(state, slashableAttestation1.getValidatorIndices()); - spec.checkIndexRange(state, slashableAttestation2.getValidatorIndices()); - spec.checkShardRange(slashableAttestation1.getData().getShard()); - spec.checkShardRange(slashableAttestation2.getData().getShard()); - - if (slashableAttestation1.getData().equals(slashableAttestation2.getData())) { - return failedResult("slashable_vote_data_1 != slashable_vote_data_2"); - } - - if (!(spec.is_double_vote(slashableAttestation1.getData(), slashableAttestation2.getData()) - || spec.is_surround_vote( - slashableAttestation1.getData(), slashableAttestation2.getData()))) { - return failedResult("no slashing conditions found"); - } - - if (!spec.verify_slashable_attestation(state, slashableAttestation1)) { - return failedResult("slashableAttestation1 is incorrect"); - } - - if (!spec.verify_slashable_attestation(state, slashableAttestation2)) { - return failedResult("slashableAttestation2 is incorrect"); + try { + spec.verify_attester_slashing(state, attesterSlashing); + return VerificationResult.PASSED; + } catch (Exception e) { + return VerificationResult.failedResult(e.getMessage()); } - - ReadList intersection = - slashableAttestation1.getValidatorIndices().intersection( - slashableAttestation2.getValidatorIndices()); - if (intersection.stream() - .noneMatch(i -> state.getValidatorRegistry().get(i).getSlashed())) { - return failedResult("spec assertion failed"); - } - - return PASSED; } } diff --git a/consensus/src/main/java/org/ethereum/beacon/consensus/verifier/operation/DepositVerifier.java b/consensus/src/main/java/org/ethereum/beacon/consensus/verifier/operation/DepositVerifier.java index 1d0c4bc0a..52856fe05 100644 --- a/consensus/src/main/java/org/ethereum/beacon/consensus/verifier/operation/DepositVerifier.java +++ b/consensus/src/main/java/org/ethereum/beacon/consensus/verifier/operation/DepositVerifier.java @@ -1,25 +1,19 @@ package org.ethereum.beacon.consensus.verifier.operation; -import static org.ethereum.beacon.consensus.verifier.VerificationResult.PASSED; -import static org.ethereum.beacon.consensus.verifier.VerificationResult.failedResult; - import org.ethereum.beacon.consensus.BeaconChainSpec; import org.ethereum.beacon.consensus.verifier.OperationVerifier; import org.ethereum.beacon.consensus.verifier.VerificationResult; import org.ethereum.beacon.core.BeaconState; import org.ethereum.beacon.core.operations.Deposit; -import org.ethereum.beacon.core.operations.deposit.DepositData; import org.ethereum.beacon.ssz.SSZBuilder; import org.ethereum.beacon.ssz.SSZSerializer; -import tech.pegasys.artemis.ethereum.core.Hash32; -import tech.pegasys.artemis.util.bytes.BytesValue; /** * Verifies {@link Deposit} beacon chain operation. * * @see Deposit * @see Deposits + * href="https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#deposits">Deposits * in the spec. */ public class DepositVerifier implements OperationVerifier { @@ -31,35 +25,13 @@ public DepositVerifier(BeaconChainSpec spec) { this.spec = spec; } - BytesValue serialize(DepositData depositData) { - // Let serialized_deposit_data be the serialized form of deposit.deposit_data. - // It should be 8 bytes for deposit_data.amount - // followed by 8 bytes for deposit_data.timestamp - // and then the DepositInput bytes. - // That is, it should match deposit_data in the Ethereum 1.0 deposit contract of which - // the hash was placed into the Merkle tree. - return depositData - .getAmount().toBytesBigEndian() - .concat(depositData.getTimestamp().toBytesBigEndian()) - .concat(ssz.encode2(depositData.getDepositInput())); - } - @Override public VerificationResult verify(Deposit deposit, BeaconState state) { - BytesValue serializedDepositData = serialize(deposit.getDepositData()); - Hash32 serializedDataHash = spec.hash(serializedDepositData); - - if (!spec.verify_merkle_branch( - serializedDataHash, - deposit.getProof(), - spec.getConstants().getDepositContractTreeDepth(), - deposit.getIndex(), - state.getLatestEth1Data().getDepositRoot())) { - - return failedResult( - "merkle proof verification failed, serialized_data_hash = %s", serializedDataHash); + try { + spec.verify_deposit(state, deposit); + return VerificationResult.PASSED; + } catch (Exception e) { + return VerificationResult.failedResult(e.getMessage()); } - - return PASSED; } } diff --git a/consensus/src/main/java/org/ethereum/beacon/consensus/verifier/operation/ProposerSlashingVerifier.java b/consensus/src/main/java/org/ethereum/beacon/consensus/verifier/operation/ProposerSlashingVerifier.java index 6a278ff27..c58c592ef 100644 --- a/consensus/src/main/java/org/ethereum/beacon/consensus/verifier/operation/ProposerSlashingVerifier.java +++ b/consensus/src/main/java/org/ethereum/beacon/consensus/verifier/operation/ProposerSlashingVerifier.java @@ -1,22 +1,17 @@ package org.ethereum.beacon.consensus.verifier.operation; -import static org.ethereum.beacon.consensus.verifier.VerificationResult.PASSED; -import static org.ethereum.beacon.consensus.verifier.VerificationResult.failedResult; -import static org.ethereum.beacon.core.spec.SignatureDomains.BEACON_BLOCK; - import org.ethereum.beacon.consensus.BeaconChainSpec; import org.ethereum.beacon.consensus.verifier.OperationVerifier; import org.ethereum.beacon.consensus.verifier.VerificationResult; import org.ethereum.beacon.core.BeaconState; import org.ethereum.beacon.core.operations.ProposerSlashing; -import org.ethereum.beacon.core.state.ValidatorRecord; /** * Verifies {@link ProposerSlashing} beacon chain operation. * * @see ProposerSlashing * @see Proposer + * href="https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#proposer-slashings">Proposer * slashings in the spec. */ public class ProposerSlashingVerifier implements OperationVerifier { @@ -29,50 +24,11 @@ public ProposerSlashingVerifier(BeaconChainSpec spec) { @Override public VerificationResult verify(ProposerSlashing proposerSlashing, BeaconState state) { - spec.checkIndexRange(state, proposerSlashing.getProposerIndex()); - - if (!spec.slot_to_epoch(proposerSlashing - .getHeader1() - .getSlot()) - .equals(spec.slot_to_epoch(proposerSlashing.getHeader2().getSlot()))) { - return failedResult("proposer_slashing.header_1.epoch != proposer_slashing.header_2.epoch"); - } - - if (proposerSlashing - .getHeader1() - .equals(proposerSlashing.getHeader2())) { - return failedResult("proposer_slashing.header_1 == proposer_slashing.header_2"); - } - - ValidatorRecord proposer = - state.getValidatorRegistry().get(proposerSlashing.getProposerIndex()); - if (proposer.getSlashed()) { - return failedResult( - "proposer was already slashed"); + try { + spec.verify_proposer_slashing(state, proposerSlashing); + return VerificationResult.PASSED; + } catch (Exception e) { + return VerificationResult.failedResult(e.getMessage()); } - - if (!spec.bls_verify( - proposer.getPubKey(), - spec.signed_root(proposerSlashing.getHeader1()), - proposerSlashing.getHeader1().getSignature(), - spec.get_domain( - state.getFork(), - spec.slot_to_epoch(proposerSlashing.getHeader1().getSlot()), - BEACON_BLOCK))) { - return failedResult("header_1.signature is invalid"); - } - - if (!spec.bls_verify( - proposer.getPubKey(), - spec.signed_root(proposerSlashing.getHeader2()), - proposerSlashing.getHeader2().getSignature(), - spec.get_domain( - state.getFork(), - spec.slot_to_epoch(proposerSlashing.getHeader2().getSlot()), - BEACON_BLOCK))) { - return failedResult("header_2.signature is invalid"); - } - - return PASSED; } } diff --git a/consensus/src/main/java/org/ethereum/beacon/consensus/verifier/operation/TransferVerifier.java b/consensus/src/main/java/org/ethereum/beacon/consensus/verifier/operation/TransferVerifier.java index d41e1c837..67eafc159 100644 --- a/consensus/src/main/java/org/ethereum/beacon/consensus/verifier/operation/TransferVerifier.java +++ b/consensus/src/main/java/org/ethereum/beacon/consensus/verifier/operation/TransferVerifier.java @@ -1,23 +1,16 @@ package org.ethereum.beacon.consensus.verifier.operation; -import static org.ethereum.beacon.consensus.verifier.VerificationResult.PASSED; -import static org.ethereum.beacon.consensus.verifier.VerificationResult.failedResult; - import org.ethereum.beacon.consensus.BeaconChainSpec; import org.ethereum.beacon.consensus.verifier.OperationVerifier; import org.ethereum.beacon.consensus.verifier.VerificationResult; import org.ethereum.beacon.core.BeaconState; import org.ethereum.beacon.core.operations.Transfer; -import org.ethereum.beacon.core.spec.SignatureDomains; -import org.ethereum.beacon.core.state.ValidatorRecord; -import org.ethereum.beacon.core.types.Gwei; -import tech.pegasys.artemis.util.uint.UInt64s; /** * Verifies {@link Transfer} beacon chain operation. * * @see Transfers + * href="https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#transfers">Transfers * section in the spec. */ public class TransferVerifier implements OperationVerifier { @@ -30,87 +23,11 @@ public TransferVerifier(BeaconChainSpec spec) { @Override public VerificationResult verify(Transfer transfer, BeaconState state) { - - if (transfer.getSender().greaterEqual(state.getValidatorRegistry().size())) { - return failedResult( - "sender index does not exist, registry size: %s", state.getValidatorRegistry().size()); - } - - if (transfer.getRecipient().greaterEqual(state.getValidatorRegistry().size())) { - return failedResult( - "recipient index does not exist, registry size: %s", state.getValidatorRegistry().size()); - } - - Gwei fromBalance = state.getValidatorBalances().get(transfer.getSender()); - - // Verify the amount and fee aren't individually too big (for anti-overflow purposes) - if (fromBalance.less(UInt64s.max(transfer.getAmount(), transfer.getFee()))) { - return failedResult( - "insufficient funds to cover amount or fee, balance=%s when transfer.amount=%s, transfer.fee=%s", - fromBalance, transfer.getAmount(), transfer.getFee()); + try { + spec.verify_transfer(state, transfer); + return VerificationResult.PASSED; + } catch (Exception e) { + return VerificationResult.failedResult(e.getMessage()); } - - /* assert ( - state.validator_balances[transfer.sender] == transfer.amount + transfer.fee or - state.validator_balances[transfer.sender] >= transfer.amount + transfer.fee + MIN_DEPOSIT_AMOUNT - ) */ - if (!fromBalance.equals(transfer.getFee().plus(transfer.getAmount())) - && fromBalance.less( - transfer - .getAmount() - .plus(transfer.getFee()) - .plus(spec.getConstants().getMinDepositAmount()))) { - return failedResult( - "insufficient funds to cover transfer, balance=%s when transfer total=%s", - fromBalance, transfer.getFee().plus(transfer.getAmount())); - } - - // Verify that state.slot == transfer.slot. - if (!state.getSlot().equals(transfer.getSlot())) { - return failedResult("transfer slot is invalid, state.slot=%s when transfer.slot=%s"); - } - - ValidatorRecord sender = state.getValidatorRegistry().get(transfer.getSender()); - - /* assert ( - get_current_epoch(state) >= state.validator_registry[transfer.sender].withdrawable_epoch or - state.validator_registry[transfer.sender].activation_epoch == FAR_FUTURE_EPOCH - )*/ - if (spec.get_current_epoch(state).less(sender.getWithdrawableEpoch()) - && !sender.getActivationEpoch().equals(spec.getConstants().getFarFutureEpoch())) { - return failedResult("epoch validation failed"); - } - - /* assert ( - state.validator_registry[transfer.sender].withdrawal_credentials == - BLS_WITHDRAWAL_PREFIX_BYTE + hash(transfer.pubkey)[1:] - ) */ - if (!sender - .getWithdrawalCredentials() - .equals( - spec.getConstants() - .getBlsWithdrawalPrefixByte() - .concat(spec.hash(transfer.getPubkey()).slice(1)))) { - return failedResult("withdrawal_credentials do not match"); - } - - /* assert bls_verify( - pubkey=transfer.pubkey, - message_hash=signed_root(transfer), - signature=transfer.signature, - domain=get_domain(state.fork, slot_to_epoch(transfer.slot), DOMAIN_TRANSFER) - ) */ - if (!spec.bls_verify( - transfer.getPubkey(), - spec.signed_root(transfer), - transfer.getSignature(), - spec.get_domain( - state.getFork(), - spec.slot_to_epoch(transfer.getSlot()), - SignatureDomains.TRANSFER))) { - return failedResult("signature verification failed"); - } - - return PASSED; } } diff --git a/consensus/src/main/java/org/ethereum/beacon/consensus/verifier/operation/VoluntaryExitVerifier.java b/consensus/src/main/java/org/ethereum/beacon/consensus/verifier/operation/VoluntaryExitVerifier.java index fef910d1c..2c4abc20c 100644 --- a/consensus/src/main/java/org/ethereum/beacon/consensus/verifier/operation/VoluntaryExitVerifier.java +++ b/consensus/src/main/java/org/ethereum/beacon/consensus/verifier/operation/VoluntaryExitVerifier.java @@ -1,22 +1,17 @@ package org.ethereum.beacon.consensus.verifier.operation; -import static org.ethereum.beacon.consensus.verifier.VerificationResult.PASSED; -import static org.ethereum.beacon.consensus.verifier.VerificationResult.failedResult; -import static org.ethereum.beacon.core.spec.SignatureDomains.VOLUNTARY_EXIT; - import org.ethereum.beacon.consensus.BeaconChainSpec; import org.ethereum.beacon.consensus.verifier.OperationVerifier; import org.ethereum.beacon.consensus.verifier.VerificationResult; import org.ethereum.beacon.core.BeaconState; import org.ethereum.beacon.core.operations.VoluntaryExit; -import org.ethereum.beacon.core.state.ValidatorRecord; /** * Verifies {@link VoluntaryExit} beacon chain operation. * * @see VoluntaryExit * @see Voluntary + * href="https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#voluntary-exits">Voluntary * exits in the spec. */ public class VoluntaryExitVerifier implements OperationVerifier { @@ -29,44 +24,11 @@ public VoluntaryExitVerifier(BeaconChainSpec spec) { @Override public VerificationResult verify(VoluntaryExit voluntaryExit, BeaconState state) { - spec.checkIndexRange(state, voluntaryExit.getValidatorIndex()); - - ValidatorRecord validator = state.getValidatorRegistry().get(voluntaryExit.getValidatorIndex()); - - // Verify the validator has not yet exited - if (!validator.getExitEpoch().equals(spec.getConstants().getFarFutureEpoch())) { - return failedResult("validator #%s has already exited", voluntaryExit.getValidatorIndex()); - } - - // Verify the validator has not initiated an exit - if (validator.getInitiatedExit()) { - return failedResult("validator #%s has already initiated an exit", - voluntaryExit.getValidatorIndex()); + try { + spec.verify_voluntary_exit(state, voluntaryExit); + return VerificationResult.PASSED; + } catch (Exception e) { + return VerificationResult.failedResult(e.getMessage()); } - - // Exits must specify an epoch when they become valid; they are not valid before then - if (!(spec.get_current_epoch(state).greaterEqual(voluntaryExit.getEpoch()) && - spec.get_current_epoch(state).minus(validator.getActivationEpoch()) - .greaterEqual(spec.getConstants().getPersistentCommitteePeriod()))) { - return failedResult("validator #%s exit epoch boundaries are violated, min exit epoch %s but got %s", - validator.getActivationEpoch().plus(spec.getConstants().getPersistentCommitteePeriod()), - spec.get_current_epoch(state)); - } - - /* assert bls_verify( - pubkey=validator.pubkey, - message_hash=signed_root(exit), - signature=exit.signature, - domain=get_domain(state.fork, exit.epoch, DOMAIN_VOLUNTARY_EXIT) - ) */ - if (!spec.bls_verify( - validator.getPubKey(), - spec.signed_root(voluntaryExit), - voluntaryExit.getSignature(), - spec.get_domain(state.getFork(), voluntaryExit.getEpoch(), VOLUNTARY_EXIT))) { - return failedResult("failed to verify signature"); - } - - return PASSED; } } diff --git a/consensus/src/test/java/org/ethereum/beacon/consensus/BeaconChainSpecTest.java b/consensus/src/test/java/org/ethereum/beacon/consensus/BeaconChainSpecTest.java index 65633c967..1f8aa0fef 100644 --- a/consensus/src/test/java/org/ethereum/beacon/consensus/BeaconChainSpecTest.java +++ b/consensus/src/test/java/org/ethereum/beacon/consensus/BeaconChainSpecTest.java @@ -9,8 +9,8 @@ import java.util.Random; import java.util.function.Function; import java.util.stream.Collectors; +import java.util.stream.IntStream; import org.ethereum.beacon.consensus.hasher.ObjectHasher; -import org.ethereum.beacon.consensus.hasher.SSZObjectHasher; import org.ethereum.beacon.consensus.transition.InitialStateTransition; import org.ethereum.beacon.consensus.util.CachingBeaconChainSpec; import org.ethereum.beacon.core.BeaconBlock; @@ -19,11 +19,12 @@ import org.ethereum.beacon.core.BeaconState; import org.ethereum.beacon.core.MutableBeaconState; import org.ethereum.beacon.core.operations.Deposit; -import org.ethereum.beacon.core.operations.deposit.DepositInput; +import org.ethereum.beacon.core.operations.deposit.DepositData; import org.ethereum.beacon.core.spec.SpecConstants; import org.ethereum.beacon.core.state.Eth1Data; import org.ethereum.beacon.core.types.BLSPubkey; import org.ethereum.beacon.core.types.BLSSignature; +import org.ethereum.beacon.core.types.Gwei; import org.ethereum.beacon.core.types.ShardNumber; import org.ethereum.beacon.core.types.SlotNumber; import org.ethereum.beacon.core.types.Time; @@ -39,6 +40,7 @@ import tech.pegasys.artemis.util.bytes.Bytes96; import tech.pegasys.artemis.util.bytes.BytesValue; import tech.pegasys.artemis.util.uint.UInt64; +import tech.pegasys.artemis.util.uint.UInt64s; public class BeaconChainSpecTest { @@ -51,11 +53,11 @@ public void shuffleTest0() throws Exception { BytesValue bytes = BytesValue.wrap(new byte[]{(byte) 1, (byte) 256, (byte) 65656}); int expectedInt = 817593; - Hash32 hash = Hashes.keccak256(bytes); + Hash32 hash = Hashes.sha256(bytes); int res = Bytes3.wrap(hash, 0).asUInt24BigEndian().getValue(); -// int[] actual = spec.shuffle(sample, Hashes.keccak256(bytes)); +// int[] actual = spec.shuffle(sample, Hashes.sha256(bytes)); // int[] expected = new int[]{2, 4, 10, 7, 5, 6, 9, 8, 1, 3}; // // Assert.assertArrayEquals(expected, actual); @@ -98,14 +100,13 @@ public void shuffleTest1() throws Exception { System.out.println(map); } - private DepositInput createDepositInput() { - DepositInput depositInput = - new DepositInput( - BLSPubkey.wrap(Bytes48.TRUE), - Hashes.keccak256(BytesValue.fromHexString("aa")), - BLSSignature.wrap(Bytes96.ZERO)); - - return depositInput; + private DepositData createDepositData() { + return new DepositData( + BLSPubkey.wrap(Bytes48.TRUE), + Hashes.sha256(BytesValue.fromHexString("aa")), + Gwei.ZERO, + BLSSignature.wrap(Bytes96.ZERO) + ); } @Test @@ -113,7 +114,7 @@ public void testHashTreeRoot1() { BeaconChainSpec spec = BeaconChainSpec.createWithDefaults(); // Hash32 expected = // Hash32.fromHexString("0x1a2017aea008e5bb8b3eb79d031f14347018353f1c58fc3a54e9fc7af7ab2fe1"); - Hash32 actual = spec.hash_tree_root(createDepositInput()); + Hash32 actual = spec.hash_tree_root(createDepositData()); // assertEquals(expected, actual); } @@ -123,9 +124,10 @@ public void headerAndBlockHashesAreEqual() { BeaconChainSpec spec = BeaconChainSpec.createWithDefaults(); BeaconBlock emptyBlock = spec.get_empty_block(); BeaconBlockBody body = - new BeaconBlockBody( + BeaconBlockBody.create( emptyBlock.getBody().getRandaoReveal(), emptyBlock.getBody().getEth1Data(), + emptyBlock.getBody().getGraffiti(), emptyBlock.getBody().getProposerSlashings().listCopy(), emptyBlock.getBody().getAttesterSlashings().listCopy(), AttestationTestUtil.createRandomList(rnd, 10), @@ -140,7 +142,7 @@ public void headerAndBlockHashesAreEqual() { body, emptyBlock.getSignature()); BeaconBlockHeader header = spec.get_temporary_block_header(block); - assertEquals(spec.signed_root(block), spec.signed_root(header)); + assertEquals(spec.signing_root(block), spec.signing_root(header)); } @Ignore @@ -154,7 +156,7 @@ public void committeeTest1() { Random rnd = new Random(1); Time genesisTime = Time.of(10 * 60); - Eth1Data eth1Data = new Eth1Data(Hash32.random(rnd), Hash32.random(rnd)); + Eth1Data eth1Data = new Eth1Data(Hash32.random(rnd), UInt64.ZERO, Hash32.random(rnd)); SpecConstants specConstants = new SpecConstants() { @@ -179,7 +181,7 @@ public ShardNumber getShardCount() { } }; BeaconChainSpec spec = new CachingBeaconChainSpec( - specConstants, Hashes::keccak256, ObjectHasher.createSSZOverKeccak256(specConstants), false, true); + specConstants, Hashes::sha256, ObjectHasher.createSSZOverSHA256(specConstants), false, true); System.out.println("Generating deposits..."); List deposits = TestUtils.generateRandomDepositsWithoutSig(rnd, spec, validatorCount); @@ -191,20 +193,18 @@ public ShardNumber getShardCount() { spec.get_empty_block()); MutableBeaconState state = initialState.createMutableCopy(); - for(int i = 1; i < 128; i++) { - System.out.println("get_epoch_committee_count(" + i + ") = " + - spec.get_epoch_committee_count(i)); - } + System.out.println("get_epoch_committee_count() = " + + spec.get_epoch_committee_count(state, spec.getConstants().getGenesisEpoch())); for (SlotNumber slot : genesisSlot.iterateTo(genesisSlot.plus(SlotNumber.of(epochLength)))) { System.out.println("Slot #" + slot + " beacon proposer: " - + spec.get_beacon_proposer_index(state, slot) + + spec.get_beacon_proposer_index(state) + " committee: " + spec.get_crosslink_committees_at_slot(state, slot)); System.out.println("Slot #" + slot + " beacon proposer: " - + spec.get_beacon_proposer_index(state, slot) + + spec.get_beacon_proposer_index(state) + " committee: " + spec.get_crosslink_committees_at_slot(state, slot).stream() .map(c -> c.getShard() + ": [" + c.getCommittee().size() + "]") @@ -212,4 +212,28 @@ public ShardNumber getShardCount() { ); } } + + @Test + public void computeCommittee2ProducesCorrectResult() { + BeaconChainSpec spec = BeaconChainSpec.createWithDefaults(); + + int committeeSize = 128; + int totalCommittees = 64; + int validatorCount = committeeSize * totalCommittees + 11; + List validatorIndices = IntStream.range(0, validatorCount).mapToObj(ValidatorIndex::new).collect( + Collectors.toList()); + Hash32 seed = Hash32.random(new Random()); + + List actualIndices = new ArrayList<>(); + for (UInt64 i : UInt64s.iterate(UInt64.ZERO, UInt64.valueOf(totalCommittees))) { + List committee = spec.compute_committee(validatorIndices, seed, i, UInt64.valueOf(totalCommittees)); + List committee2 = spec.compute_committee2(validatorIndices, seed, i, UInt64.valueOf(totalCommittees)); + assertEquals(committee, committee2); + + actualIndices.addAll(committee); + } + + actualIndices.sort(ValidatorIndex::compareTo); + assertEquals(validatorIndices, actualIndices); + } } diff --git a/consensus/src/test/java/org/ethereum/beacon/consensus/TestUtils.java b/consensus/src/test/java/org/ethereum/beacon/consensus/TestUtils.java index ef96a40df..68e1819bc 100644 --- a/consensus/src/test/java/org/ethereum/beacon/consensus/TestUtils.java +++ b/consensus/src/test/java/org/ethereum/beacon/consensus/TestUtils.java @@ -4,11 +4,9 @@ import org.ethereum.beacon.core.operations.Deposit; import org.ethereum.beacon.core.operations.deposit.DepositData; -import org.ethereum.beacon.core.operations.deposit.DepositInput; import org.ethereum.beacon.core.state.Fork; import org.ethereum.beacon.core.types.BLSPubkey; import org.ethereum.beacon.core.types.BLSSignature; -import org.ethereum.beacon.core.types.Time; import org.ethereum.beacon.crypto.BLS381; import org.ethereum.beacon.crypto.BLS381.KeyPair; import org.ethereum.beacon.crypto.BLS381.PrivateKey; @@ -17,8 +15,10 @@ import org.javatuples.Pair; 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.collections.ReadVector; import tech.pegasys.artemis.util.uint.UInt64; import java.util.ArrayList; @@ -47,16 +47,15 @@ private synchronized static Pair, List> generateRandomDep List validatorsKeys = new ArrayList<>(); for (int i = 0; i < count; i++) { KeyPair keyPair = KeyPair.create(PrivateKey.create(Bytes32.random(rnd))); - Hash32 proofOfPossession = Hash32.random(rnd); - DepositInput depositInputWithoutSignature = new DepositInput( + Hash32 withdrawalCredentials = Hash32.random(rnd); + DepositData depositDataWithoutSignature = new DepositData( BLSPubkey.wrap(Bytes48.leftPad(keyPair.getPublic().getEncodedBytes())), - proofOfPossession, + withdrawalCredentials, + spec.getConstants().getMaxEffectiveBalance(), BLSSignature.wrap(Bytes96.ZERO) ); - Hash32 msgHash = spec.signed_root(depositInputWithoutSignature); - UInt64 domain = - spec.get_domain( - Fork.EMPTY, spec.getConstants().getGenesisEpoch(), DEPOSIT); + Hash32 msgHash = spec.signing_root(depositDataWithoutSignature); + UInt64 domain = spec.get_domain(Bytes4.ZERO, DEPOSIT); Signature signature = BLS381 .sign(MessageParameters.create(msgHash, domain), keyPair); @@ -64,16 +63,14 @@ private synchronized static Pair, List> generateRandomDep Deposit deposit = new Deposit( - Collections.singletonList(Hash32.random(rnd)), - UInt64.ZERO, + ReadVector.wrap(Collections.singletonList(Hash32.random(rnd)), Integer::new), + UInt64.valueOf(i), new DepositData( - spec.getConstants().getMaxDepositAmount(), - Time.of(0), - new DepositInput( - BLSPubkey.wrap(Bytes48.leftPad(keyPair.getPublic().getEncodedBytes())), - proofOfPossession, - BLSSignature.wrap(signature.getEncoded())) - )); + BLSPubkey.wrap(Bytes48.leftPad(keyPair.getPublic().getEncodedBytes())), + withdrawalCredentials, + spec.getConstants().getMaxEffectiveBalance(), + BLSSignature.wrap(signature.getEncoded())) + ); deposits.add(deposit); } @@ -85,17 +82,18 @@ public static List generateRandomDepositsWithoutSig(Random rnd, BeaconC UInt64 counter = UInt64.ZERO; for (int i = 0; i < count; i++) { - Hash32 proofOfPossession = Hash32.random(rnd); + Hash32 withdrawalCredentials = Hash32.random(rnd); BLSPubkey pubkey = BLSPubkey.wrap(Bytes48.leftPad(counter.toBytesBigEndian())); Deposit deposit = new Deposit( - Collections.singletonList(Hash32.random(rnd)), + ReadVector.wrap(Collections.singletonList(Hash32.random(rnd)), Integer::new), counter, new DepositData( - spec.getConstants().getMaxDepositAmount(), - Time.of(0), - new DepositInput(pubkey, proofOfPossession, BLSSignature.ZERO))); + pubkey, + withdrawalCredentials, + spec.getConstants().getMaxEffectiveBalance(), + BLSSignature.ZERO)); deposits.add(deposit); counter = counter.increment(); } diff --git a/consensus/src/test/java/org/ethereum/beacon/consensus/hasher/SSZObjectHasherTest.java b/consensus/src/test/java/org/ethereum/beacon/consensus/hasher/SSZObjectHasherTest.java index b44cddedf..c8c558996 100644 --- a/consensus/src/test/java/org/ethereum/beacon/consensus/hasher/SSZObjectHasherTest.java +++ b/consensus/src/test/java/org/ethereum/beacon/consensus/hasher/SSZObjectHasherTest.java @@ -21,7 +21,7 @@ /** Tests of {@link SSZObjectHasher} */ public class SSZObjectHasherTest { private static byte[] DEFAULT_HASH = - Hashes.keccak256(BytesValue.fromHexString("aa")).getArrayUnsafe(); + Hashes.sha256(BytesValue.fromHexString("aa")).getArrayUnsafe(); private static Sign.Signature DEFAULT_SIG = new Sign.Signature(); static { @@ -35,7 +35,7 @@ public class SSZObjectHasherTest { public void setup() { SSZHasher sszHasher = new SSZBuilder() .withExplicitAnnotations(false) - .buildHasher(Hashes::keccak256); + .buildHasher(Hashes::sha256); this.sszHasher = new SSZObjectHasher(sszHasher); } @@ -103,9 +103,9 @@ public void simpleTruncateTest() { @Test public void list32Test() { List hashes = new ArrayList<>(); - hashes.add(Hashes.keccak256(BytesValue.fromHexString("aa")).getArrayUnsafe()); - hashes.add(Hashes.keccak256(BytesValue.fromHexString("bb")).getArrayUnsafe()); - hashes.add(Hashes.keccak256(BytesValue.fromHexString("cc")).getArrayUnsafe()); + hashes.add(Hashes.sha256(BytesValue.fromHexString("aa")).getArrayUnsafe()); + hashes.add(Hashes.sha256(BytesValue.fromHexString("bb")).getArrayUnsafe()); + hashes.add(Hashes.sha256(BytesValue.fromHexString("cc")).getArrayUnsafe()); AttestationRecord attestationRecord = new AttestationRecord( 123, @@ -167,7 +167,7 @@ public void listTest() { BytesValue hash = sszHasher.getHash(anotherObjects); assertEquals( BytesValue.fromHexString( - "0x6d3a1eb14c6b37eb4645044d0c1bf38284b408eab24e89238a8058f3b921e5d9"), + "0x79674903e05afe130f6b198098124b6cdaeeb2e62da2b14630eac79193332c52"), hash); } diff --git a/consensus/src/test/java/org/ethereum/beacon/consensus/transition/InitialStateTransitionTest.java b/consensus/src/test/java/org/ethereum/beacon/consensus/transition/InitialStateTransitionTest.java index 867d4b15c..ac185524f 100644 --- a/consensus/src/test/java/org/ethereum/beacon/consensus/transition/InitialStateTransitionTest.java +++ b/consensus/src/test/java/org/ethereum/beacon/consensus/transition/InitialStateTransitionTest.java @@ -20,7 +20,7 @@ public class InitialStateTransitionTest { public void handleChainStartCorrectly() { Random rnd = new Random(); Time genesisTime = Time.castFrom(UInt64.random(rnd)); - Eth1Data eth1Data = new Eth1Data(Hash32.random(rnd), Hash32.random(rnd)); + Eth1Data eth1Data = new Eth1Data(Hash32.random(rnd), UInt64.ZERO, Hash32.random(rnd)); BeaconChainSpec spec = BeaconChainSpec.createWithDefaults(); InitialStateTransition initialStateTransition = diff --git a/consensus/src/test/java/org/ethereum/beacon/consensus/transition/PerEpochTransitionTest.java b/consensus/src/test/java/org/ethereum/beacon/consensus/transition/PerEpochTransitionTest.java index 65fcb0ceb..b18026f93 100644 --- a/consensus/src/test/java/org/ethereum/beacon/consensus/transition/PerEpochTransitionTest.java +++ b/consensus/src/test/java/org/ethereum/beacon/consensus/transition/PerEpochTransitionTest.java @@ -24,7 +24,7 @@ public class PerEpochTransitionTest { public void test1() { Random rnd = new Random(); Time genesisTime = Time.castFrom(UInt64.random(rnd)); - Eth1Data eth1Data = new Eth1Data(Hash32.random(rnd), Hash32.random(rnd)); + Eth1Data eth1Data = new Eth1Data(Hash32.random(rnd), UInt64.ZERO, Hash32.random(rnd)); SpecConstants specConstants = new SpecConstants() { @Override @@ -54,9 +54,9 @@ public SlotNumber.EpochLength getSlotsPerEpoch() { // check validators penalized for inactivity for (int i = 0; i < deposits.size(); i++) { Gwei balanceBefore = - states[0].getValidatorBalances().get(ValidatorIndex.of(i)); + states[0].getBalances().get(ValidatorIndex.of(i)); Gwei balanceAfter = - epochState.getValidatorBalances().get(ValidatorIndex.of(i)); + epochState.getBalances().get(ValidatorIndex.of(i)); Assert.assertTrue(balanceAfter.less(balanceBefore)); } } diff --git a/consensus/src/test/java/org/ethereum/beacon/consensus/transition/PerSlotTransitionTest.java b/consensus/src/test/java/org/ethereum/beacon/consensus/transition/PerSlotTransitionTest.java index 72751e237..57fbd3585 100644 --- a/consensus/src/test/java/org/ethereum/beacon/consensus/transition/PerSlotTransitionTest.java +++ b/consensus/src/test/java/org/ethereum/beacon/consensus/transition/PerSlotTransitionTest.java @@ -22,7 +22,7 @@ public class PerSlotTransitionTest { public void test1() { Random rnd = new Random(); Time genesisTime = Time.castFrom(UInt64.random(rnd)); - Eth1Data eth1Data = new Eth1Data(Hash32.random(rnd), Hash32.random(rnd)); + Eth1Data eth1Data = new Eth1Data(Hash32.random(rnd), UInt64.ZERO, Hash32.random(rnd)); SpecConstants specConstants = new SpecConstants() { @Override diff --git a/core/src/main/java/org/ethereum/beacon/core/BeaconBlock.java b/core/src/main/java/org/ethereum/beacon/core/BeaconBlock.java index 524a2b8ee..f21f2df8f 100644 --- a/core/src/main/java/org/ethereum/beacon/core/BeaconBlock.java +++ b/core/src/main/java/org/ethereum/beacon/core/BeaconBlock.java @@ -27,7 +27,7 @@ * * @see BeaconBlockBody * @see BeaconBlock + * href="https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#beaconblock">BeaconBlock * in the spec */ @SSZSerializable diff --git a/core/src/main/java/org/ethereum/beacon/core/BeaconBlockBody.java b/core/src/main/java/org/ethereum/beacon/core/BeaconBlockBody.java index 1aefc3766..ac086f85e 100644 --- a/core/src/main/java/org/ethereum/beacon/core/BeaconBlockBody.java +++ b/core/src/main/java/org/ethereum/beacon/core/BeaconBlockBody.java @@ -3,7 +3,6 @@ import static java.util.Collections.emptyList; import com.google.common.base.Objects; -import java.util.ArrayList; import java.util.List; import org.ethereum.beacon.core.operations.Attestation; import org.ethereum.beacon.core.operations.Deposit; @@ -11,13 +10,12 @@ import org.ethereum.beacon.core.operations.Transfer; import org.ethereum.beacon.core.operations.VoluntaryExit; import org.ethereum.beacon.core.operations.slashing.AttesterSlashing; -import org.ethereum.beacon.core.spec.InitialValues; import org.ethereum.beacon.core.state.Eth1Data; import org.ethereum.beacon.core.types.BLSSignature; import org.ethereum.beacon.ssz.annotation.SSZ; import org.ethereum.beacon.ssz.annotation.SSZSerializable; +import tech.pegasys.artemis.util.bytes.Bytes32; import tech.pegasys.artemis.util.collections.ReadList; -import tech.pegasys.artemis.util.collections.WriteList; /** * Beacon block body. @@ -26,7 +24,7 @@ * * @see BeaconBlock * @see BeaconBlockBody + * href="https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#beaconblockbody">BeaconBlockBody * in the spec */ @SSZSerializable @@ -34,9 +32,10 @@ public class BeaconBlockBody { /** A body where all lists are empty. */ public static final BeaconBlockBody EMPTY = - new BeaconBlockBody( - InitialValues.EMPTY_SIGNATURE, + BeaconBlockBody.create( + BLSSignature.ZERO, Eth1Data.EMPTY, + Bytes32.ZERO, emptyList(), emptyList(), emptyList(), @@ -48,36 +47,62 @@ public class BeaconBlockBody { @SSZ private final BLSSignature randaoReveal; /** Eth1 data that is observed by proposer. */ @SSZ private final Eth1Data eth1Data; + /** Analogue to Eth1 Extra Data. */ + @SSZ private final Bytes32 graffiti; /** A list of proposer slashing challenges. */ - @SSZ private final List proposerSlashingsList; + @SSZ private final ReadList proposerSlashings; /** A list of attester slashing challenges. */ - @SSZ private final List attesterSlashingsList; + @SSZ private final ReadList attesterSlashings; /** A list of attestations. */ - @SSZ private final List attestationsList; + @SSZ private final ReadList attestations; /** A list of validator deposit proofs. */ - @SSZ private final List depositsList; + @SSZ private final ReadList deposits; /** A list of validator exits. */ - @SSZ private final List voluntaryExitsList; + @SSZ private final ReadList voluntaryExits; /** A list of transfers. */ - @SSZ private final List transferList; + @SSZ private final ReadList transfers; public BeaconBlockBody( BLSSignature randaoReveal, Eth1Data eth1Data, - List proposerSlashingsList, - List attesterSlashingsList, - List attestationsList, - List depositsList, - List voluntaryExitsList, - List transferList) { + Bytes32 graffiti, + ReadList proposerSlashings, + ReadList attesterSlashings, + ReadList attestations, + ReadList deposits, + ReadList voluntaryExits, + ReadList transfers) { this.randaoReveal = randaoReveal; this.eth1Data = eth1Data; - this.proposerSlashingsList = proposerSlashingsList; - this.attesterSlashingsList = attesterSlashingsList; - this.attestationsList = attestationsList; - this.depositsList = depositsList; - this.voluntaryExitsList = voluntaryExitsList; - this.transferList = transferList; + this.graffiti = graffiti; + this.proposerSlashings = proposerSlashings; + this.attesterSlashings = attesterSlashings; + this.attestations = attestations; + this.deposits = deposits; + this.voluntaryExits = voluntaryExits; + this.transfers = transfers; + } + + public static BeaconBlockBody create( + BLSSignature randaoReveal, + Eth1Data eth1Data, + Bytes32 graffiti, + List proposerSlashings, + List attesterSlashings, + List attestations, + List deposits, + List voluntaryExits, + List transfers) { + return new BeaconBlockBody( + randaoReveal, + eth1Data, + graffiti, + ReadList.wrap(proposerSlashings, Integer::new), + ReadList.wrap(attesterSlashings, Integer::new), + ReadList.wrap(attestations, Integer::new), + ReadList.wrap(deposits, Integer::new), + ReadList.wrap(voluntaryExits, Integer::new), + ReadList.wrap(transfers, Integer::new)); } public BLSSignature getRandaoReveal() { @@ -88,70 +113,32 @@ public Eth1Data getEth1Data() { return eth1Data; } + public Bytes32 getGraffiti() { + return graffiti; + } + public ReadList getProposerSlashings() { - return WriteList.wrap(proposerSlashingsList, Integer::intValue); + return proposerSlashings; } public ReadList getAttesterSlashings() { - return WriteList.wrap(attesterSlashingsList, Integer::intValue); + return attesterSlashings; } public ReadList getAttestations() { - return WriteList.wrap(attestationsList, Integer::intValue); + return attestations; } public ReadList getDeposits() { - return WriteList.wrap(depositsList, Integer::intValue); + return deposits; } public ReadList getVoluntaryExits() { - return WriteList.wrap(voluntaryExitsList, Integer::intValue); + return voluntaryExits; } public ReadList getTransfers() { - return WriteList.wrap(transferList, Integer::intValue); - } - - /** - * @deprecated for serialization only - */ - public List getProposerSlashingsList() { - return proposerSlashingsList; - } - - /** - * @deprecated for serialization only - */ - public List getAttesterSlashingsList() { - return attesterSlashingsList; - } - - /** - * @deprecated for serialization only - */ - public List getAttestationsList() { - return attestationsList; - } - - /** - * @deprecated for serialization only - */ - public List getDepositsList() { - return depositsList; - } - - /** - * @deprecated for serialization only - */ - public List getVoluntaryExitsList() { - return voluntaryExitsList; - } - - /** - * @deprecated for serialization only - */ - public List getTransferList() { - return transferList; + return transfers; } @Override @@ -165,12 +152,13 @@ public boolean equals(Object object) { BeaconBlockBody blockBody = (BeaconBlockBody) object; return Objects.equal(randaoReveal, blockBody.randaoReveal) && Objects.equal(eth1Data, blockBody.eth1Data) - && Objects.equal(proposerSlashingsList, blockBody.proposerSlashingsList) - && Objects.equal(attesterSlashingsList, blockBody.attesterSlashingsList) - && Objects.equal(attestationsList, blockBody.attestationsList) - && Objects.equal(depositsList, blockBody.depositsList) - && Objects.equal(voluntaryExitsList, blockBody.voluntaryExitsList) - && Objects.equal(transferList, blockBody.transferList); + && Objects.equal(graffiti, blockBody.graffiti) + && Objects.equal(proposerSlashings, blockBody.proposerSlashings) + && Objects.equal(attesterSlashings, blockBody.attesterSlashings) + && Objects.equal(attestations, blockBody.attestations) + && Objects.equal(deposits, blockBody.deposits) + && Objects.equal(voluntaryExits, blockBody.voluntaryExits) + && Objects.equal(transfers, blockBody.transfers); } @Override @@ -178,11 +166,12 @@ public int hashCode() { return Objects.hashCode( randaoReveal, eth1Data, - proposerSlashingsList, - attesterSlashingsList, - attestationsList, - depositsList, - voluntaryExitsList, - transferList); + graffiti, + proposerSlashings, + attesterSlashings, + attestations, + deposits, + voluntaryExits, + transfers); } } diff --git a/core/src/main/java/org/ethereum/beacon/core/BeaconBlockHeader.java b/core/src/main/java/org/ethereum/beacon/core/BeaconBlockHeader.java index fd097c0b7..94b11a3eb 100644 --- a/core/src/main/java/org/ethereum/beacon/core/BeaconBlockHeader.java +++ b/core/src/main/java/org/ethereum/beacon/core/BeaconBlockHeader.java @@ -4,7 +4,6 @@ import java.util.Optional; import java.util.function.Function; import javax.annotation.Nullable; -import org.ethereum.beacon.core.spec.InitialValues; import org.ethereum.beacon.core.spec.SpecConstants; import org.ethereum.beacon.core.types.BLSSignature; import org.ethereum.beacon.core.types.Hashable; @@ -17,7 +16,7 @@ * Beacon block header structure. * * @see BeaconBlockHeader + * href="https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#beaconblockheader">BeaconBlockHeader * in the spec. */ @SSZSerializable @@ -25,7 +24,7 @@ public class BeaconBlockHeader implements Hashable { public static final BeaconBlockHeader EMPTY = new BeaconBlockHeader( - SlotNumber.ZERO, Hash32.ZERO, Hash32.ZERO, Hash32.ZERO, InitialValues.EMPTY_SIGNATURE); + SlotNumber.ZERO, Hash32.ZERO, Hash32.ZERO, Hash32.ZERO, BLSSignature.ZERO); @SSZ private final SlotNumber slot; @SSZ private final Hash32 previousBlockRoot; diff --git a/core/src/main/java/org/ethereum/beacon/core/BeaconState.java b/core/src/main/java/org/ethereum/beacon/core/BeaconState.java index 02b3a9e42..c0644b502 100644 --- a/core/src/main/java/org/ethereum/beacon/core/BeaconState.java +++ b/core/src/main/java/org/ethereum/beacon/core/BeaconState.java @@ -8,7 +8,6 @@ import org.ethereum.beacon.core.spec.SpecConstants; import org.ethereum.beacon.core.state.BeaconStateImpl; import org.ethereum.beacon.core.state.Eth1Data; -import org.ethereum.beacon.core.state.Eth1DataVote; import org.ethereum.beacon.core.state.Fork; import org.ethereum.beacon.core.state.PendingAttestation; import org.ethereum.beacon.core.state.ValidatorRecord; @@ -31,7 +30,7 @@ * * @see BeaconBlock * @see BeaconState + * href="https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#beacon-state">BeaconState * in the spec */ public interface BeaconState extends ObservableComposite { @@ -52,6 +51,10 @@ static BeaconState getEmpty(SpecConstants specConst) { Collections.nCopies(specConst.getLatestActiveIndexRootsLength().intValue(), Hash32.ZERO)); ret.getLatestSlashedBalances().addAll( Collections.nCopies(specConst.getLatestSlashedExitLength().intValue(), Gwei.ZERO)); + ret.getPreviousCrosslinks().addAll( + Collections.nCopies(specConst.getShardCount().intValue(), Crosslink.EMPTY)); + ret.getCurrentCrosslinks().addAll( + Collections.nCopies(specConst.getShardCount().intValue(), Crosslink.EMPTY)); return ret; } @@ -72,87 +75,76 @@ static BeaconState getEmpty(SpecConstants specConst) { @SSZ(order = 3) ReadList getValidatorRegistry(); /** Validator balances. */ - @SSZ(order = 4) ReadList getValidatorBalances(); - - /** Slot number of last validator registry change. */ - @SSZ(order = 5) EpochNumber getValidatorRegistryUpdateEpoch(); + @SSZ(order = 4) ReadList getBalances(); /* ******* Randomness and committees ********* */ /** The most recent randao mixes. */ - @SSZ(order = 6, vectorLengthVar = "spec.LATEST_RANDAO_MIXES_LENGTH") + @SSZ(order = 5, vectorLengthVar = "spec.LATEST_RANDAO_MIXES_LENGTH") ReadVector getLatestRandaoMixes(); - @SSZ(order = 7) ShardNumber getPreviousShufflingStartShard(); - - @SSZ(order = 8) ShardNumber getCurrentShufflingStartShard(); - - @SSZ(order = 9) EpochNumber getPreviousShufflingEpoch(); - - @SSZ(order = 10) EpochNumber getCurrentShufflingEpoch(); - - @SSZ(order = 11) Hash32 getPreviousShufflingSeed(); - - @SSZ(order = 12) Hash32 getCurrentShufflingSeed(); + @SSZ(order = 6) ShardNumber getLatestStartShard(); /********* Finality **********/ - @SSZ(order = 13) ReadList getPreviousEpochAttestations(); + @SSZ(order = 7) ReadList getPreviousEpochAttestations(); - @SSZ(order = 14) ReadList getCurrentEpochAttestations(); + @SSZ(order = 8) ReadList getCurrentEpochAttestations(); /** Latest justified epoch before {@link #getCurrentJustifiedEpoch()}. */ - @SSZ(order = 15) EpochNumber getPreviousJustifiedEpoch(); + @SSZ(order = 9) EpochNumber getPreviousJustifiedEpoch(); /** Latest justified epoch. */ - @SSZ(order = 16) EpochNumber getCurrentJustifiedEpoch(); + @SSZ(order = 10) EpochNumber getCurrentJustifiedEpoch(); - @SSZ(order = 17) Hash32 getPreviousJustifiedRoot(); + @SSZ(order = 11) Hash32 getPreviousJustifiedRoot(); - @SSZ(order = 18) Hash32 getCurrentJustifiedRoot(); + @SSZ(order = 12) Hash32 getCurrentJustifiedRoot(); /** Bitfield of latest justified slots (epochs). */ - @SSZ(order = 19) Bitfield64 getJustificationBitfield(); + @SSZ(order = 13) Bitfield64 getJustificationBitfield(); /** Latest finalized slot. */ - @SSZ(order = 20) EpochNumber getFinalizedEpoch(); + @SSZ(order = 14) EpochNumber getFinalizedEpoch(); - @SSZ(order = 21) Hash32 getFinalizedRoot(); + @SSZ(order = 15) Hash32 getFinalizedRoot(); /* ******* Recent state ********* */ /** Latest crosslink record for each shard. */ - @SSZ(order = 22) ReadList getPreviousCrosslinks(); + @SSZ(order = 16, vectorLengthVar = "spec.SHARD_COUNT") + ReadVector getCurrentCrosslinks(); - @SSZ(order = 23) ReadList getCurrentCrosslinks(); + @SSZ(order = 17, vectorLengthVar = "spec.SHARD_COUNT") + ReadVector getPreviousCrosslinks(); - @SSZ(order = 24, vectorLengthVar = "spec.SLOTS_PER_HISTORICAL_ROOT") + @SSZ(order = 18, vectorLengthVar = "spec.SLOTS_PER_HISTORICAL_ROOT") ReadVector getLatestBlockRoots(); - @SSZ(order = 25, vectorLengthVar = "spec.SLOTS_PER_HISTORICAL_ROOT") + @SSZ(order = 19, vectorLengthVar = "spec.SLOTS_PER_HISTORICAL_ROOT") ReadVector getLatestStateRoots(); - @SSZ(order = 26, vectorLengthVar = "spec.LATEST_ACTIVE_INDEX_ROOTS_LENGTH") + @SSZ(order = 20, vectorLengthVar = "spec.LATEST_ACTIVE_INDEX_ROOTS_LENGTH") ReadVector getLatestActiveIndexRoots(); /** Balances slashed at every withdrawal period */ - @SSZ(order = 27, vectorLengthVar = "spec.LATEST_SLASHED_EXIT_LENGTH") + @SSZ(order = 21, vectorLengthVar = "spec.LATEST_SLASHED_EXIT_LENGTH") ReadVector getLatestSlashedBalances(); - @SSZ(order = 28) BeaconBlockHeader getLatestBlockHeader(); + @SSZ(order = 22) BeaconBlockHeader getLatestBlockHeader(); - @SSZ(order = 29) ReadList getHistoricalRoots(); + @SSZ(order = 23) ReadList getHistoricalRoots(); /* ******* PoW receipt root ********* */ /** Latest processed eth1 data. */ - @SSZ(order = 30) Eth1Data getLatestEth1Data(); + @SSZ(order = 24) Eth1Data getLatestEth1Data(); /** Eth1 data that voting is still in progress for. */ - @SSZ(order = 31) ReadList getEth1DataVotes(); + @SSZ(order = 25) ReadList getEth1DataVotes(); /** The most recent Eth1 deposit index */ - @SSZ(order = 32) UInt64 getDepositIndex(); + @SSZ(order = 26) UInt64 getDepositIndex(); /** * Returns mutable copy of this state. Any changes made to returned copy shouldn't affect this @@ -165,15 +157,9 @@ default boolean equalsHelper(BeaconState other) { && getGenesisTime().equals(other.getGenesisTime()) && getFork().equals(other.getFork()) && getValidatorRegistry().equals(other.getValidatorRegistry()) - && getValidatorBalances().equals(other.getValidatorBalances()) - && getValidatorRegistryUpdateEpoch().equals(other.getValidatorRegistryUpdateEpoch()) + && getBalances().equals(other.getBalances()) && getLatestRandaoMixes().equals(other.getLatestRandaoMixes()) - && getPreviousShufflingStartShard().equals(other.getPreviousShufflingStartShard()) - && getCurrentShufflingStartShard().equals(other.getCurrentShufflingStartShard()) - && getPreviousShufflingEpoch().equals(other.getPreviousShufflingEpoch()) - && getCurrentShufflingEpoch().equals(other.getCurrentShufflingEpoch()) - && getPreviousShufflingSeed().equals(other.getPreviousShufflingSeed()) - && getCurrentShufflingSeed().equals(other.getCurrentShufflingSeed()) + && getLatestStartShard().equals(other.getLatestStartShard()) && getPreviousEpochAttestations().equals(other.getPreviousEpochAttestations()) && getCurrentEpochAttestations().equals(other.getCurrentEpochAttestations()) && getPreviousJustifiedEpoch().equals(other.getPreviousJustifiedEpoch()) @@ -201,11 +187,10 @@ default String toStringShort(@Nullable SpecConstants spec) { + "@ " + getSlot().toString(spec, getGenesisTime()) + ", " + getFork().toString(spec) + ", validators: " + getValidatorRegistry().size() - + " updated at epoch " + getValidatorRegistryUpdateEpoch().toString(spec) + ", just/final epoch: " + getCurrentJustifiedEpoch().toString(spec) + "/" + getFinalizedEpoch().toString(spec); if (spec != null) { ret += ", latestBlocks=[..."; - for (SlotNumber slot : getSlot().minus(3).iterateTo(getSlot())) { + for (SlotNumber slot : getSlot().minusSat(3).iterateTo(getSlot())) { Hash32 blockRoot = getLatestBlockRoots().get(slot.modulo(spec.getSlotsPerHistoricalRoot())); ret += ", " + blockRoot.toStringShort(); } diff --git a/core/src/main/java/org/ethereum/beacon/core/MutableBeaconState.java b/core/src/main/java/org/ethereum/beacon/core/MutableBeaconState.java index 8674db747..a2b1ca065 100644 --- a/core/src/main/java/org/ethereum/beacon/core/MutableBeaconState.java +++ b/core/src/main/java/org/ethereum/beacon/core/MutableBeaconState.java @@ -31,24 +31,12 @@ public interface MutableBeaconState extends BeaconState { WriteList getValidatorRegistry(); @Override - WriteList getValidatorBalances(); - - void setValidatorRegistryUpdateEpoch(EpochNumber validatorRegistryUpdateEpoch); + WriteList getBalances(); @Override WriteVector getLatestRandaoMixes(); - void setPreviousShufflingStartShard(ShardNumber previousShufflingStartShard); - - void setCurrentShufflingStartShard(ShardNumber currentShufflingStartShard); - - void setPreviousShufflingEpoch(EpochNumber previousShufflingEpoch); - - void setCurrentShufflingEpoch(EpochNumber currentShufflingEpoch); - - void setPreviousShufflingSeed(Hash32 previousEpochRandaoMix); - - void setCurrentShufflingSeed(Hash32 currentEpochRandaoMix); + void setLatestStartShard(ShardNumber latestStartShard); void setPreviousJustifiedEpoch(EpochNumber previousJustifiedEpoch); @@ -96,7 +84,7 @@ public interface MutableBeaconState extends BeaconState { void setLatestEth1Data(Eth1Data latestEth1Data); @Override - WriteList getEth1DataVotes(); + WriteList getEth1DataVotes(); void setDepositIndex(UInt64 depositIndex); diff --git a/core/src/main/java/org/ethereum/beacon/core/operations/Attestation.java b/core/src/main/java/org/ethereum/beacon/core/operations/Attestation.java index f41198c82..66d8cec5e 100644 --- a/core/src/main/java/org/ethereum/beacon/core/operations/Attestation.java +++ b/core/src/main/java/org/ethereum/beacon/core/operations/Attestation.java @@ -31,17 +31,17 @@ public class Attestation { /** Proof of custody bitfield. */ @SSZ private final Bitfield custodyBitfield; /** A product of aggregation of signatures from different validators to {@link #data}. */ - @SSZ private final BLSSignature aggregateSignature; + @SSZ private final BLSSignature signature; public Attestation( Bitfield aggregationBitfield, AttestationData data, Bitfield custodyBitfield, - BLSSignature aggregateSignature) { + BLSSignature signature) { this.aggregationBitfield = aggregationBitfield; this.data = data; this.custodyBitfield = custodyBitfield; - this.aggregateSignature = aggregateSignature; + this.signature = signature; } public AttestationData getData() { @@ -56,8 +56,8 @@ public Bitfield getCustodyBitfield() { return custodyBitfield; } - public BLSSignature getAggregateSignature() { - return aggregateSignature; + public BLSSignature getSignature() { + return signature; } @Override @@ -68,7 +68,7 @@ public boolean equals(Object o) { return Objects.equal(data, that.data) && Objects.equal(aggregationBitfield, that.aggregationBitfield) && Objects.equal(custodyBitfield, that.custodyBitfield) - && Objects.equal(aggregateSignature, that.aggregateSignature); + && Objects.equal(signature, that.signature); } @Override @@ -76,7 +76,7 @@ public int hashCode() { int result = data.hashCode(); result = 31 * result + aggregationBitfield.hashCode(); result = 31 * result + custodyBitfield.hashCode(); - result = 31 * result + aggregateSignature.hashCode(); + result = 31 * result + signature.hashCode(); return result; } @@ -94,13 +94,13 @@ public String toString(@Nullable SpecConstants spec,@Nullable Time beaconStart) + data.toString(spec, beaconStart) + ", attesters=" + getSignerIndices() + ", cusodyBits=" + custodyBitfield - + ", sig=" + aggregateSignature + + ", sig=" + signature + "]"; } public String toStringShort(@Nullable SpecConstants spec) { - return getData().getSlot().toStringNumber(spec) + "/" - + getData().getShard().toString(spec) + "/" + return "epoch=" + getData().getTargetEpoch().toString(spec) + "/" + + getData().getShard().toString() + "/" + getData().getBeaconBlockRoot().toStringShort() + "/" + getSignerIndices(); } diff --git a/core/src/main/java/org/ethereum/beacon/core/operations/Deposit.java b/core/src/main/java/org/ethereum/beacon/core/operations/Deposit.java index 6d2f0c66e..47ff99db1 100644 --- a/core/src/main/java/org/ethereum/beacon/core/operations/Deposit.java +++ b/core/src/main/java/org/ethereum/beacon/core/operations/Deposit.java @@ -1,12 +1,12 @@ package org.ethereum.beacon.core.operations; import com.google.common.base.Objects; -import java.util.List; import org.ethereum.beacon.core.BeaconBlockBody; import org.ethereum.beacon.core.operations.deposit.DepositData; import org.ethereum.beacon.ssz.annotation.SSZ; import org.ethereum.beacon.ssz.annotation.SSZSerializable; import tech.pegasys.artemis.ethereum.core.Hash32; +import tech.pegasys.artemis.util.collections.ReadVector; import tech.pegasys.artemis.util.uint.UInt64; /** @@ -22,19 +22,20 @@ public class Deposit { /** A branch of receipt's Merkle trie of the deposit contract on PoW net. */ - @SSZ private final List proof; + @SSZ(vectorLengthVar = "spec.DEPOSIT_CONTRACT_TREE_DEPTH") + private final ReadVector proof; /** An index of receipt's entry in the trie. */ @SSZ private final UInt64 index; /** Deposit data. */ - @SSZ private final DepositData depositData; + @SSZ private final DepositData data; - public Deposit(List proof, UInt64 index, DepositData depositData) { + public Deposit(ReadVector proof, UInt64 index, DepositData data) { this.proof = proof; this.index = index; - this.depositData = depositData; + this.data = data; } - public List getProof() { + public ReadVector getProof() { return proof; } @@ -42,8 +43,8 @@ public UInt64 getIndex() { return index; } - public DepositData getDepositData() { - return depositData; + public DepositData getData() { + return data; } @Override @@ -53,16 +54,16 @@ public boolean equals(Object o) { Deposit deposit = (Deposit) o; return proof.equals(deposit.proof) && Objects.equal(index, deposit.index) - && Objects.equal(depositData, deposit.depositData); + && Objects.equal(data, deposit.data); } @Override public String toString() { return "Deposit[" + "idx=" + index - + "amount=" + depositData.getAmount() - + "time=" + depositData.getTimestamp() - + "pubkey=" + depositData.getDepositInput().getPubKey() + + "pubkey=" + data.getPubKey() + + "withdrawalCredentials=" + data.getWithdrawalCredentials() + + "amount=" + data.getAmount() + "]"; } } diff --git a/core/src/main/java/org/ethereum/beacon/core/operations/attestation/AttestationData.java b/core/src/main/java/org/ethereum/beacon/core/operations/attestation/AttestationData.java index 736bdd933..dd6444783 100644 --- a/core/src/main/java/org/ethereum/beacon/core/operations/attestation/AttestationData.java +++ b/core/src/main/java/org/ethereum/beacon/core/operations/attestation/AttestationData.java @@ -6,7 +6,6 @@ import org.ethereum.beacon.core.spec.SpecConstants; import org.ethereum.beacon.core.types.EpochNumber; import org.ethereum.beacon.core.types.ShardNumber; -import org.ethereum.beacon.core.types.SlotNumber; import org.ethereum.beacon.core.types.Time; import org.ethereum.beacon.ssz.annotation.SSZ; import org.ethereum.beacon.ssz.annotation.SSZSerializable; @@ -17,7 +16,7 @@ * * @see Attestation * @see AttestationData + * href="https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#attestationdata">AttestationData * in the spec */ @SSZSerializable @@ -25,8 +24,6 @@ public class AttestationData { // LMD GHOST vote: - /** Slot number. */ - @SSZ private final SlotNumber slot; /** Root of the signed beacon block. */ @SSZ private final Hash32 beaconBlockRoot; @@ -36,6 +33,8 @@ public class AttestationData { @SSZ private final EpochNumber sourceEpoch; /** FFG source block root. */ @SSZ private final Hash32 sourceRoot; + /** FFG target epoch. */ + @SSZ private final EpochNumber targetEpoch; /** FFG target block root. */ @SSZ private final Hash32 targetRoot; @@ -43,32 +42,28 @@ public class AttestationData { /** Shard number. */ @SSZ private final ShardNumber shard; - /** Previous crosslink. */ - @SSZ private final Crosslink previousCrosslink; + /** Previous crosslink root. */ + @SSZ private final Hash32 previousCrosslinkRoot; /** Data from the shard since the last attestation. */ @SSZ private final Hash32 crosslinkDataRoot; public AttestationData( - SlotNumber slot, Hash32 beaconBlockRoot, EpochNumber sourceEpoch, Hash32 sourceRoot, + EpochNumber targetEpoch, Hash32 targetRoot, ShardNumber shard, - Crosslink previousCrosslink, + Hash32 previousCrosslinkRoot, Hash32 crosslinkDataRoot) { - this.slot = slot; - this.shard = shard; this.beaconBlockRoot = beaconBlockRoot; - this.targetRoot = targetRoot; - this.crosslinkDataRoot = crosslinkDataRoot; - this.previousCrosslink = previousCrosslink; this.sourceEpoch = sourceEpoch; this.sourceRoot = sourceRoot; - } - - public SlotNumber getSlot() { - return slot; + this.targetEpoch = targetEpoch; + this.targetRoot = targetRoot; + this.shard = shard; + this.previousCrosslinkRoot = previousCrosslinkRoot; + this.crosslinkDataRoot = crosslinkDataRoot; } public ShardNumber getShard() { @@ -79,6 +74,10 @@ public Hash32 getBeaconBlockRoot() { return beaconBlockRoot; } + public EpochNumber getTargetEpoch() { + return targetEpoch; + } + public Hash32 getTargetRoot() { return targetRoot; } @@ -87,8 +86,8 @@ public Hash32 getCrosslinkDataRoot() { return crosslinkDataRoot; } - public Crosslink getPreviousCrosslink() { - return previousCrosslink; + public Hash32 getPreviousCrosslinkRoot() { + return previousCrosslinkRoot; } public EpochNumber getSourceEpoch() { @@ -104,26 +103,26 @@ public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; AttestationData that = (AttestationData) o; - return Objects.equal(slot, that.slot) - && Objects.equal(shard, that.shard) + return Objects.equal(shard, that.shard) && Objects.equal(beaconBlockRoot, that.beaconBlockRoot) && Objects.equal(targetRoot, that.targetRoot) && Objects.equal(crosslinkDataRoot, that.crosslinkDataRoot) - && Objects.equal(previousCrosslink, that.previousCrosslink) + && Objects.equal(previousCrosslinkRoot, that.previousCrosslinkRoot) && Objects.equal(sourceEpoch, that.sourceEpoch) + && Objects.equal(targetEpoch, that.targetEpoch) && Objects.equal(sourceRoot, that.sourceRoot); } @Override public int hashCode() { - int result = slot != null ? slot.hashCode() : 0; - result = 31 * result + (shard != null ? shard.hashCode() : 0); + int result = shard != null ? shard.hashCode() : 0; result = 31 * result + (beaconBlockRoot != null ? beaconBlockRoot.hashCode() : 0); result = 31 * result + (targetRoot != null ? targetRoot.hashCode() : 0); result = 31 * result + (crosslinkDataRoot != null ? crosslinkDataRoot.hashCode() : 0); - result = 31 * result + (previousCrosslink != null ? previousCrosslink.hashCode() : 0); + result = 31 * result + (previousCrosslinkRoot != null ? previousCrosslinkRoot.hashCode() : 0); result = 31 * result + (sourceEpoch != null ? sourceEpoch.hashCode() : 0); result = 31 * result + (sourceRoot != null ? sourceRoot.hashCode() : 0); + result = 31 * result + (targetEpoch != null ? targetEpoch.hashCode() : 0); return result; } @@ -133,13 +132,13 @@ public String toString() { } public String toString(@Nullable SpecConstants spec,@Nullable Time beaconStart) { - return "AttestationData[slot=" - + slot.toStringNumber(spec) - + ", shard=" + shard.toString(spec) + return "AttestationData[shard=" + + shard.toString() + ", beaconBlock=" + beaconBlockRoot.toStringShort() + + ", targetEpoch=" + targetEpoch.toString(spec) + ", targetRoot=" + targetRoot.toStringShort() + ", shardBlock=" + crosslinkDataRoot.toStringShort() - + ", previousCrosslink=" + previousCrosslink.toString(spec) + + ", previousCrosslinkRoot=" + previousCrosslinkRoot.toStringShort() + ", sourceEpoch=" + sourceEpoch.toString(spec) + ", sourceRoot=" + sourceRoot.toStringShort() +"]"; diff --git a/core/src/main/java/org/ethereum/beacon/core/operations/attestation/Crosslink.java b/core/src/main/java/org/ethereum/beacon/core/operations/attestation/Crosslink.java index 8fc077dfb..f02f95fdf 100644 --- a/core/src/main/java/org/ethereum/beacon/core/operations/attestation/Crosslink.java +++ b/core/src/main/java/org/ethereum/beacon/core/operations/attestation/Crosslink.java @@ -12,21 +12,24 @@ * A Crosslink record. * * @see Crosslink + * href="https://github.com/ethereum/eth2.0-specs/blob/0.6.1/specs/core/0_beacon-chain.md#crosslink">Crosslink * in the spec. */ @SSZSerializable public class Crosslink { - public static final Crosslink EMPTY = new Crosslink(EpochNumber.ZERO, Hash32.ZERO); + public static final Crosslink EMPTY = new Crosslink(EpochNumber.ZERO, Hash32.ZERO, Hash32.ZERO); /** Epoch number. */ @SSZ private final EpochNumber epoch; - /** Shard data since the previous crosslink. */ + /** Root of the previous crosslink. */ + @SSZ private final Hash32 previousCrosslinkRoot; + /** Root of the crosslinked shard data since the previous crosslink. */ @SSZ private final Hash32 crosslinkDataRoot; - public Crosslink(EpochNumber epoch, Hash32 crosslinkDataRoot) { + public Crosslink(EpochNumber epoch, Hash32 previousCrosslinkRoot, Hash32 crosslinkDataRoot) { this.epoch = epoch; + this.previousCrosslinkRoot = previousCrosslinkRoot; this.crosslinkDataRoot = crosslinkDataRoot; } @@ -34,6 +37,10 @@ public EpochNumber getEpoch() { return epoch; } + public Hash32 getPreviousCrosslinkRoot() { + return previousCrosslinkRoot; + } + public Hash32 getCrosslinkDataRoot() { return crosslinkDataRoot; } @@ -48,12 +55,13 @@ public boolean equals(Object object) { } Crosslink crosslink = (Crosslink) object; return Objects.equal(epoch, crosslink.epoch) + && Objects.equal(previousCrosslinkRoot, crosslink.previousCrosslinkRoot) && Objects.equal(crosslinkDataRoot, crosslink.crosslinkDataRoot); } @Override public int hashCode() { - return Objects.hashCode(epoch, crosslinkDataRoot); + return Objects.hashCode(epoch, previousCrosslinkRoot, crosslinkDataRoot); } @Override @@ -64,6 +72,7 @@ public String toString() { public String toString(SpecConstants spec) { return MoreObjects.toStringHelper(this) .add("epoch", epoch.toString(spec)) + .add("previousCrosslinkRoot", previousCrosslinkRoot.toStringShort()) .add("crosslinkDataRoot", crosslinkDataRoot.toStringShort()) .toString(); } diff --git a/core/src/main/java/org/ethereum/beacon/core/operations/deposit/DepositData.java b/core/src/main/java/org/ethereum/beacon/core/operations/deposit/DepositData.java index 0ec9300a5..bf9291e19 100644 --- a/core/src/main/java/org/ethereum/beacon/core/operations/deposit/DepositData.java +++ b/core/src/main/java/org/ethereum/beacon/core/operations/deposit/DepositData.java @@ -2,46 +2,56 @@ import com.google.common.base.Objects; import org.ethereum.beacon.core.operations.Deposit; +import org.ethereum.beacon.core.types.BLSPubkey; +import org.ethereum.beacon.core.types.BLSSignature; import org.ethereum.beacon.core.types.Gwei; import org.ethereum.beacon.core.types.Time; import org.ethereum.beacon.ssz.annotation.SSZ; import org.ethereum.beacon.ssz.annotation.SSZSerializable; -import tech.pegasys.artemis.util.uint.UInt64; +import tech.pegasys.artemis.ethereum.core.Hash32; /** * A data of validator registration deposit. * * @see Deposit * @see DepositData + * href="https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#depositdata">DepositData * in the spec */ @SSZSerializable public class DepositData { - /** Value in Gwei. */ + /** BLS public key. */ + @SSZ private final BLSPubkey pubKey; + /** Withdrawal credentials. */ + @SSZ private final Hash32 withdrawalCredentials; + /** Amount in Gwei. */ @SSZ private final Gwei amount; - /** Timestamp from deposit contract. */ - @SSZ private final Time timestamp; - /** Deposit parameters. */ - @SSZ private final DepositInput depositInput; + /** Container self-signature */ + @SSZ private final BLSSignature signature; - public DepositData(Gwei amount, Time timestamp, DepositInput depositInput) { + public DepositData( + BLSPubkey pubKey, Hash32 withdrawalCredentials, Gwei amount, BLSSignature signature) { + this.pubKey = pubKey; + this.withdrawalCredentials = withdrawalCredentials; this.amount = amount; - this.timestamp = timestamp; - this.depositInput = depositInput; + this.signature = signature; } public Gwei getAmount() { return amount; } - public Time getTimestamp() { - return timestamp; + public BLSPubkey getPubKey() { + return pubKey; } - public DepositInput getDepositInput() { - return depositInput; + public Hash32 getWithdrawalCredentials() { + return withdrawalCredentials; + } + + public BLSSignature getSignature() { + return signature; } @Override @@ -49,8 +59,9 @@ public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; DepositData that = (DepositData) o; - return Objects.equal(depositInput, that.depositInput) + return Objects.equal(pubKey, that.pubKey) + && Objects.equal(withdrawalCredentials, that.withdrawalCredentials) && Objects.equal(amount, that.amount) - && Objects.equal(timestamp, that.timestamp); + && Objects.equal(signature, that.signature); } } diff --git a/core/src/main/java/org/ethereum/beacon/core/operations/deposit/DepositInput.java b/core/src/main/java/org/ethereum/beacon/core/operations/deposit/DepositInput.java deleted file mode 100644 index d36b52550..000000000 --- a/core/src/main/java/org/ethereum/beacon/core/operations/deposit/DepositInput.java +++ /dev/null @@ -1,58 +0,0 @@ -package org.ethereum.beacon.core.operations.deposit; - -import com.google.common.base.Objects; -import org.ethereum.beacon.core.operations.Deposit; -import org.ethereum.beacon.core.types.BLSPubkey; -import org.ethereum.beacon.core.types.BLSSignature; -import org.ethereum.beacon.ssz.annotation.SSZ; -import org.ethereum.beacon.ssz.annotation.SSZSerializable; -import tech.pegasys.artemis.ethereum.core.Hash32; - -/** - * An input parameters of deposit contract. - * - * @see DepositData - * @see Deposit - * @see DepositInput - * in the spec - */ -@SSZSerializable -public class DepositInput { - - /** BLS public key. */ - @SSZ private final BLSPubkey pubKey; - /** Withdrawal credentials. */ - @SSZ private final Hash32 withdrawalCredentials; - /** A BLS signature of this {@link DepositInput} */ - @SSZ private final BLSSignature proofOfPossession; - - public DepositInput( - BLSPubkey pubKey, Hash32 withdrawalCredentials, BLSSignature proofOfPossession) { - this.pubKey = pubKey; - this.withdrawalCredentials = withdrawalCredentials; - this.proofOfPossession = proofOfPossession; - } - - public BLSPubkey getPubKey() { - return pubKey; - } - - public Hash32 getWithdrawalCredentials() { - return withdrawalCredentials; - } - - public BLSSignature getProofOfPossession() { - return proofOfPossession; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - DepositInput that = (DepositInput) o; - return Objects.equal(pubKey, that.pubKey) - && Objects.equal(withdrawalCredentials, that.withdrawalCredentials) - && Objects.equal(proofOfPossession, that.proofOfPossession); - } -} diff --git a/core/src/main/java/org/ethereum/beacon/core/operations/slashing/AttesterSlashing.java b/core/src/main/java/org/ethereum/beacon/core/operations/slashing/AttesterSlashing.java index 437794ada..1fd835638 100644 --- a/core/src/main/java/org/ethereum/beacon/core/operations/slashing/AttesterSlashing.java +++ b/core/src/main/java/org/ethereum/beacon/core/operations/slashing/AttesterSlashing.java @@ -8,22 +8,22 @@ @SSZSerializable public class AttesterSlashing { - @SSZ private final SlashableAttestation slashableAttestation1; - @SSZ private final SlashableAttestation slashableAttestation2; + @SSZ private final IndexedAttestation attestation1; + @SSZ private final IndexedAttestation attestation2; public AttesterSlashing( - SlashableAttestation slashableAttestation1, - SlashableAttestation slashableAttestation2) { - this.slashableAttestation1 = slashableAttestation1; - this.slashableAttestation2 = slashableAttestation2; + IndexedAttestation attestation1, + IndexedAttestation attestation2) { + this.attestation1 = attestation1; + this.attestation2 = attestation2; } - public SlashableAttestation getSlashableAttestation1() { - return slashableAttestation1; + public IndexedAttestation getAttestation1() { + return attestation1; } - public SlashableAttestation getSlashableAttestation2() { - return slashableAttestation2; + public IndexedAttestation getAttestation2() { + return attestation2; } @Override @@ -31,8 +31,8 @@ public boolean equals(Object o) { if (this == o) {return true;} if (o == null || getClass() != o.getClass()) {return false;} AttesterSlashing that = (AttesterSlashing) o; - if (!slashableAttestation1.equals(that.slashableAttestation1)) {return false;} - return slashableAttestation2.equals(that.slashableAttestation2); + if (!attestation1.equals(that.attestation1)) {return false;} + return attestation2.equals(that.attestation2); } @Override @@ -42,8 +42,8 @@ public String toString() { public String toString(@Nullable SpecConstants spec,@Nullable Time beaconStart) { return "AttesterSlashing[" - + "att1=" + slashableAttestation1.toString(spec, beaconStart) - + "att2=" + slashableAttestation2.toString(spec, beaconStart) + + "att1=" + attestation1.toString(spec, beaconStart) + + "att2=" + attestation2.toString(spec, beaconStart) + "]"; } } diff --git a/core/src/main/java/org/ethereum/beacon/core/operations/slashing/IndexedAttestation.java b/core/src/main/java/org/ethereum/beacon/core/operations/slashing/IndexedAttestation.java new file mode 100644 index 000000000..def78711b --- /dev/null +++ b/core/src/main/java/org/ethereum/beacon/core/operations/slashing/IndexedAttestation.java @@ -0,0 +1,106 @@ +package org.ethereum.beacon.core.operations.slashing; + +import com.google.common.base.Objects; +import org.ethereum.beacon.core.operations.attestation.AttestationData; +import org.ethereum.beacon.core.spec.SpecConstants; +import org.ethereum.beacon.core.types.BLSSignature; +import org.ethereum.beacon.core.types.Time; +import org.ethereum.beacon.core.types.ValidatorIndex; +import org.ethereum.beacon.ssz.annotation.SSZ; +import org.ethereum.beacon.ssz.annotation.SSZSerializable; +import tech.pegasys.artemis.util.collections.ReadList; + +import javax.annotation.Nullable; +import java.util.List; +import java.util.function.Function; + +/** + * Slashable attestation data structure. + * + * @see IndexedAttestation + * in the spec. + */ +@SSZSerializable +public class IndexedAttestation { + /** Validator indices */ + @SSZ private final ReadList custodyBit0Indices; + + @SSZ private final ReadList custodyBit1Indices; + /** Attestation data */ + @SSZ private final AttestationData data; + /** Aggregate signature */ + @SSZ private final BLSSignature signature; + + public IndexedAttestation( + List custodyBit0Indices, + List custodyBit1Indices, + AttestationData data, + BLSSignature signature) { + this( + ReadList.wrap(custodyBit0Indices, Function.identity()), + ReadList.wrap(custodyBit1Indices, Function.identity()), + data, + signature); + } + + public IndexedAttestation( + ReadList custodyBit0Indices, + ReadList custodyBit1Indices, + AttestationData data, + BLSSignature signature) { + this.custodyBit0Indices = custodyBit0Indices; + this.custodyBit1Indices = custodyBit1Indices; + this.data = data; + this.signature = signature; + } + + public ReadList getCustodyBit0Indices() { + return custodyBit0Indices; + } + + public ReadList getCustodyBit1Indices() { + return custodyBit1Indices; + } + + public AttestationData getData() { + return data; + } + + public BLSSignature getSignature() { + return signature; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + IndexedAttestation that = (IndexedAttestation) o; + return Objects.equal(custodyBit0Indices, that.custodyBit0Indices) + && Objects.equal(custodyBit1Indices, that.custodyBit1Indices) + && Objects.equal(data, that.data) + && Objects.equal(signature, that.signature); + } + + @Override + public String toString() { + return toString(null, null); + } + + public String toString(@Nullable SpecConstants spec, @Nullable Time beaconStart) { + return "IndexedAttestation[" + + "data=" + + data.toString(spec, beaconStart) + + ", custodyBit0Indices=" + + custodyBit0Indices + + ", custodyBit1Indices=" + + custodyBit1Indices + + ", sig=" + + signature + + "]"; + } +} diff --git a/core/src/main/java/org/ethereum/beacon/core/operations/slashing/SlashableAttestation.java b/core/src/main/java/org/ethereum/beacon/core/operations/slashing/SlashableAttestation.java deleted file mode 100644 index 584e43c07..000000000 --- a/core/src/main/java/org/ethereum/beacon/core/operations/slashing/SlashableAttestation.java +++ /dev/null @@ -1,92 +0,0 @@ -package org.ethereum.beacon.core.operations.slashing; - -import java.util.ArrayList; -import java.util.List; -import javax.annotation.Nullable; -import org.ethereum.beacon.core.operations.attestation.AttestationData; -import org.ethereum.beacon.core.spec.SpecConstants; -import org.ethereum.beacon.core.types.BLSSignature; -import org.ethereum.beacon.core.types.Bitfield; -import org.ethereum.beacon.core.types.Time; -import org.ethereum.beacon.core.types.ValidatorIndex; -import org.ethereum.beacon.ssz.annotation.SSZ; -import org.ethereum.beacon.ssz.annotation.SSZSerializable; -import tech.pegasys.artemis.util.collections.ReadList; -import tech.pegasys.artemis.util.collections.WriteList; - -/** - * Slashable attestation data structure. - * - * @see SlashableAttestation - * in the spec. - */ -@SSZSerializable -public class SlashableAttestation { - /** Validator indices */ - @SSZ private final List validatorIndicesList; - /** Attestation data */ - @SSZ private final AttestationData data; - /** Custody bitfield */ - @SSZ private final Bitfield custodyBitfield; - /** Aggregate signature */ - @SSZ private final BLSSignature aggregateSingature; - - public SlashableAttestation( - List validatorIndices, - AttestationData data, Bitfield custodyBitfield, - BLSSignature aggregateSingature) { - this.validatorIndicesList = new ArrayList<>(validatorIndices); - this.data = data; - this.custodyBitfield = custodyBitfield; - this.aggregateSingature = aggregateSingature; - } - - public ReadList getValidatorIndices() { - return WriteList.wrap(validatorIndicesList, Integer::valueOf); - } - - public AttestationData getData() { - return data; - } - - public Bitfield getCustodyBitfield() { - return custodyBitfield; - } - - public BLSSignature getAggregateSingature() { - return aggregateSingature; - } - - /** - * @deprecated for serialization only - */ - public List getValidatorIndicesList() { - return validatorIndicesList; - } - - @Override - public boolean equals(Object o) { - if (this == o) {return true;} - if (o == null || getClass() != o.getClass()) {return false;} - SlashableAttestation that = (SlashableAttestation) o; - if (!validatorIndicesList.equals(that.validatorIndicesList)) {return false;} - if (!data.equals(that.data)) {return false;} - if (!custodyBitfield.equals(that.custodyBitfield)) {return false;} - return aggregateSingature.equals(that.aggregateSingature); - } - - @Override - public String toString() { - return toString(null, null); - } - - public String toString(@Nullable SpecConstants spec,@Nullable Time beaconStart) { - return "SlashableAttestation[" - + "data=" + data.toString(spec, beaconStart) - + ", validators=" + validatorIndicesList - + ", custodyBits=" + custodyBitfield - + ", sig=" + aggregateSingature - + "]"; - } -} diff --git a/core/src/main/java/org/ethereum/beacon/core/spec/GweiValues.java b/core/src/main/java/org/ethereum/beacon/core/spec/GweiValues.java index b3275efb4..2868035cc 100644 --- a/core/src/main/java/org/ethereum/beacon/core/spec/GweiValues.java +++ b/core/src/main/java/org/ethereum/beacon/core/spec/GweiValues.java @@ -12,20 +12,20 @@ public interface GweiValues { Gwei MIN_DEPOSIT_AMOUNT = Gwei.ofEthers(1); // 1 ETH - Gwei MAX_DEPOSIT_AMOUNT = Gwei.ofEthers(1 << 5); // 32 ETH - Gwei FORK_CHOICE_BALANCE_INCREMENT = Gwei.ofEthers(1); // 1 ETH + Gwei MAX_EFFECTIVE_BALANCE = Gwei.ofEthers(1 << 5); // 32 ETH + Gwei EFFECTIVE_BALANCE_INCREMENT = Gwei.ofEthers(1); // 1 ETH Gwei EJECTION_BALANCE = Gwei.ofEthers(1 << 4); // 16 ETH default Gwei getMinDepositAmount() { return MIN_DEPOSIT_AMOUNT; } - default Gwei getMaxDepositAmount() { - return MAX_DEPOSIT_AMOUNT; + default Gwei getMaxEffectiveBalance() { + return MAX_EFFECTIVE_BALANCE; } - default Gwei getForkChoiceBalanceIncrement() { - return FORK_CHOICE_BALANCE_INCREMENT; + default Gwei getEffectiveBalanceIncrement() { + return EFFECTIVE_BALANCE_INCREMENT; } default Gwei getEjectionBalance() { diff --git a/core/src/main/java/org/ethereum/beacon/core/spec/InitialValues.java b/core/src/main/java/org/ethereum/beacon/core/spec/InitialValues.java index a3d13af72..2dd99ae6b 100644 --- a/core/src/main/java/org/ethereum/beacon/core/spec/InitialValues.java +++ b/core/src/main/java/org/ethereum/beacon/core/spec/InitialValues.java @@ -18,28 +18,20 @@ */ public interface InitialValues { - UInt64 GENESIS_FORK_VERSION = UInt64.ZERO; - SlotNumber GENESIS_SLOT = SlotNumber.of(1L << 32); // 2**32 - ShardNumber GENESIS_START_SHARD = ShardNumber.of(0); + SlotNumber GENESIS_SLOT = SlotNumber.ZERO; + EpochNumber GENESIS_EPOCH = EpochNumber.ZERO; EpochNumber FAR_FUTURE_EPOCH = EpochNumber.castFrom(UInt64.MAX_VALUE); // (1 << 64) - 1 Hash32 ZERO_HASH = Hash32.ZERO; - BLSSignature EMPTY_SIGNATURE = BLSSignature.ZERO; Bytes1 BLS_WITHDRAWAL_PREFIX_BYTE = Bytes1.ZERO; /* Values defined in the spec. */ - default UInt64 getGenesisForkVersion() { - return GENESIS_FORK_VERSION; - } - default SlotNumber getGenesisSlot() { return GENESIS_SLOT; } - EpochNumber getGenesisEpoch(); - - default ShardNumber getGenesisStartShard() { - return GENESIS_START_SHARD; + default EpochNumber getGenesisEpoch() { + return GENESIS_EPOCH; } default EpochNumber getFarFutureEpoch() { @@ -50,10 +42,6 @@ default Hash32 getZeroHash() { return ZERO_HASH; } - default BLSSignature getEmptySignature() { - return EMPTY_SIGNATURE; - } - default Bytes1 getBlsWithdrawalPrefixByte() { return BLS_WITHDRAWAL_PREFIX_BYTE; } diff --git a/core/src/main/java/org/ethereum/beacon/core/spec/MaxOperationsPerBlock.java b/core/src/main/java/org/ethereum/beacon/core/spec/MaxOperationsPerBlock.java index 8153daf6b..19e578887 100644 --- a/core/src/main/java/org/ethereum/beacon/core/spec/MaxOperationsPerBlock.java +++ b/core/src/main/java/org/ethereum/beacon/core/spec/MaxOperationsPerBlock.java @@ -14,7 +14,7 @@ public interface MaxOperationsPerBlock { int MAX_ATTESTATIONS = 1 << 7; // 128 int MAX_DEPOSITS = 1 << 4; // 16 int MAX_VOLUNTARY_EXITS = 1 << 4; // 16 - int MAX_TRANSFERS = 1 << 4; // 16 + int MAX_TRANSFERS = 0; /* Values defined in the spec. */ diff --git a/core/src/main/java/org/ethereum/beacon/core/spec/MiscParameters.java b/core/src/main/java/org/ethereum/beacon/core/spec/MiscParameters.java index d96ec1194..71f31ecb1 100644 --- a/core/src/main/java/org/ethereum/beacon/core/spec/MiscParameters.java +++ b/core/src/main/java/org/ethereum/beacon/core/spec/MiscParameters.java @@ -1,6 +1,5 @@ package org.ethereum.beacon.core.spec; -import org.ethereum.beacon.core.types.Gwei; import org.ethereum.beacon.core.types.ShardNumber; import org.ethereum.beacon.core.types.ValidatorIndex; import tech.pegasys.artemis.util.uint.UInt64; @@ -16,10 +15,10 @@ public interface MiscParameters { ShardNumber SHARD_COUNT = ShardNumber.of(1 << 10); // 1024 shards ValidatorIndex TARGET_COMMITTEE_SIZE = ValidatorIndex.of(1 << 7); // 128 validators - UInt64 MAX_BALANCE_CHURN_QUOTIENT = UInt64.valueOf(1 << 5); // 32 - ShardNumber BEACON_CHAIN_SHARD_NUMBER = ShardNumber.of(UInt64.MAX_VALUE); // (1 << 64) - 1 - UInt64 MAX_INDICES_PER_SLASHABLE_VOTE = UInt64.valueOf(1 << 12); - UInt64 MAX_EXIT_DEQUEUES_PER_EPOCH = UInt64.valueOf(1 << 2); // 4 + UInt64 MAX_INDICES_PER_ATTESTATION = UInt64.valueOf(1 << 12); // 4096 + UInt64 MIN_PER_EPOCH_CHURN_LIMIT = UInt64.valueOf(1 << 2); // 4 + UInt64 CHURN_LIMIT_QUOTIENT = UInt64.valueOf(1 << 16); // 65_536 + UInt64 BASE_REWARDS_PER_EPOCH = UInt64.valueOf(5); int SHUFFLE_ROUND_COUNT = 90; /* Values defined in the spec. */ @@ -32,20 +31,20 @@ default ValidatorIndex getTargetCommitteeSize() { return TARGET_COMMITTEE_SIZE; } - default UInt64 getMaxBalanceChurnQuotient() { - return MAX_BALANCE_CHURN_QUOTIENT; + default UInt64 getMaxIndicesPerAttestation() { + return MAX_INDICES_PER_ATTESTATION; } - default ShardNumber getBeaconChainShardNumber() { - return BEACON_CHAIN_SHARD_NUMBER; + default UInt64 getMinPerEpochChurnLimit() { + return MIN_PER_EPOCH_CHURN_LIMIT; } - default UInt64 getMaxIndicesPerSlashableVote() { - return MAX_INDICES_PER_SLASHABLE_VOTE; + default UInt64 getChurnLimitQuotient() { + return CHURN_LIMIT_QUOTIENT; } - default UInt64 getMaxExitDequesPerEpoch() { - return MAX_EXIT_DEQUEUES_PER_EPOCH; + default UInt64 getBaseRewardsPerEpoch() { + return BASE_REWARDS_PER_EPOCH; } default int getShuffleRoundCount() { diff --git a/core/src/main/java/org/ethereum/beacon/core/spec/RewardAndPenaltyQuotients.java b/core/src/main/java/org/ethereum/beacon/core/spec/RewardAndPenaltyQuotients.java index fbb2a7e8a..a38dca32a 100644 --- a/core/src/main/java/org/ethereum/beacon/core/spec/RewardAndPenaltyQuotients.java +++ b/core/src/main/java/org/ethereum/beacon/core/spec/RewardAndPenaltyQuotients.java @@ -12,10 +12,10 @@ public interface RewardAndPenaltyQuotients { UInt64 BASE_REWARD_QUOTIENT = UInt64.valueOf(1 << 5); // 1024 - UInt64 WHISTLEBLOWER_REWARD_QUOTIENT = UInt64.valueOf(1 << 9); // 512 - UInt64 ATTESTATION_INCLUSION_REWARD_QUOTIENT = UInt64.valueOf(1 << 3); // 8 - UInt64 INACTIVITY_PENALTY_QUOTIENT = UInt64.valueOf(1 << 24); // 16_777_216 - UInt64 MIN_PENALTY_QUOTIENT = UInt64.valueOf(1 << 5); // 32 + UInt64 WHISTLEBLOWING_REWARD_QUOTIENT = UInt64.valueOf(1 << 9); // 512 + UInt64 PROPOSER_REWARD_QUOTIENT = UInt64.valueOf(1 << 3); // 8 + UInt64 INACTIVITY_PENALTY_QUOTIENT = UInt64.valueOf(1 << 25); // 33_554_432 + UInt64 MIN_SLASHING_PENALTY_QUOTIENT = UInt64.valueOf(1 << 5); // 32 /* Values defined in the spec. */ @@ -23,19 +23,19 @@ default UInt64 getBaseRewardQuotient() { return BASE_REWARD_QUOTIENT; } - default UInt64 getWhistleblowerRewardQuotient() { - return WHISTLEBLOWER_REWARD_QUOTIENT; + default UInt64 getWhistleblowingRewardQuotient() { + return WHISTLEBLOWING_REWARD_QUOTIENT; } - default UInt64 getAttestationInclusionRewardQuotient() { - return ATTESTATION_INCLUSION_REWARD_QUOTIENT; + default UInt64 getProposerRewardQuotient() { + return PROPOSER_REWARD_QUOTIENT; } default UInt64 getInactivityPenaltyQuotient() { return INACTIVITY_PENALTY_QUOTIENT; } - default UInt64 getMinPenaltyQuotient() { - return MIN_PENALTY_QUOTIENT; + default UInt64 getMinSlashingPenaltyQuotient() { + return MIN_SLASHING_PENALTY_QUOTIENT; } } diff --git a/core/src/main/java/org/ethereum/beacon/core/spec/SignatureDomains.java b/core/src/main/java/org/ethereum/beacon/core/spec/SignatureDomains.java index 4bc6327fe..822c37878 100644 --- a/core/src/main/java/org/ethereum/beacon/core/spec/SignatureDomains.java +++ b/core/src/main/java/org/ethereum/beacon/core/spec/SignatureDomains.java @@ -11,7 +11,7 @@ */ public interface SignatureDomains { - UInt64 BEACON_BLOCK = UInt64.valueOf(0); + UInt64 BEACON_PROPOSER = UInt64.valueOf(0); UInt64 RANDAO = UInt64.valueOf(1); diff --git a/core/src/main/java/org/ethereum/beacon/core/spec/TimeParameters.java b/core/src/main/java/org/ethereum/beacon/core/spec/TimeParameters.java index 3e0fabf75..3345aca2a 100644 --- a/core/src/main/java/org/ethereum/beacon/core/spec/TimeParameters.java +++ b/core/src/main/java/org/ethereum/beacon/core/spec/TimeParameters.java @@ -20,10 +20,12 @@ public interface TimeParameters { EpochLength SLOTS_PER_EPOCH = new EpochLength(UInt64.valueOf(1 << 6)); // 64 slots EpochNumber MIN_SEED_LOOKAHEAD = EpochNumber.of(1); EpochNumber ACTIVATION_EXIT_DELAY = EpochNumber.of(1 << 2); - EpochNumber EPOCHS_PER_ETH1_VOTING_PERIOD = EpochNumber.of(1 << 4); + EpochNumber SLOTS_PER_ETH1_VOTING_PERIOD = EpochNumber.of(1 << 10); // 1024 SlotNumber SLOTS_PER_HISTORICAL_ROOT = SlotNumber.of(1 << 13); // 8,192 EpochNumber MIN_VALIDATOR_WITHDRAWABILITY_DELAY = EpochNumber.of(1 << 8); EpochNumber PERSISTENT_COMMITTEE_PERIOD = EpochNumber.of(1 << 11); // 2,048 + EpochNumber MAX_CROSSLINK_EPOCHS = EpochNumber.of(1 << 6); // 64 + EpochNumber MIN_EPOCHS_TO_INACTIVITY_PENALTY = EpochNumber.of(1 << 2); // 4 /* Values defined in the spec. */ @@ -47,8 +49,8 @@ default EpochNumber getActivationExitDelay() { return ACTIVATION_EXIT_DELAY; } - default EpochNumber getEpochsPerEth1VotingPeriod() { - return EPOCHS_PER_ETH1_VOTING_PERIOD; + default EpochNumber getSlotsPerEth1VotingPeriod() { + return SLOTS_PER_ETH1_VOTING_PERIOD; } default SlotNumber getSlotsPerHistoricalRoot() { @@ -62,4 +64,12 @@ default EpochNumber getMinValidatorWithdrawabilityDelay() { default EpochNumber getPersistentCommitteePeriod() { return PERSISTENT_COMMITTEE_PERIOD; } + + default EpochNumber getMaxCrosslinkEpochs() { + return MAX_CROSSLINK_EPOCHS; + } + + default EpochNumber getMinEpochsToInactivityPenalty() { + return MIN_EPOCHS_TO_INACTIVITY_PENALTY; + } } diff --git a/core/src/main/java/org/ethereum/beacon/core/state/BeaconStateImpl.java b/core/src/main/java/org/ethereum/beacon/core/state/BeaconStateImpl.java index e802258d9..9ff3e3d54 100644 --- a/core/src/main/java/org/ethereum/beacon/core/state/BeaconStateImpl.java +++ b/core/src/main/java/org/ethereum/beacon/core/state/BeaconStateImpl.java @@ -37,7 +37,7 @@ public class BeaconStateImpl implements MutableBeaconState { private ObsValue> validatorRegistry = obsHelper.newValue(ObservableListImpl.create(ValidatorIndex::of)); - private ObsValue> validatorBalances = + private ObsValue> balances = obsHelper.newValue(ObservableListImpl.create(ValidatorIndex::of)); private ObsValue validatorRegistryUpdateEpoch = obsHelper.newValue(EpochNumber.ZERO); @@ -45,12 +45,7 @@ public class BeaconStateImpl implements MutableBeaconState { private ObsValue> latestRandaoMixes = obsHelper.newValue(ObservableListImpl.create(EpochNumber::of)); - private ObsValue previousShufflingStartShard = obsHelper.newValue(ShardNumber.ZERO); - private ObsValue currentShufflingStartShard = obsHelper.newValue(ShardNumber.ZERO); - private ObsValue previousShufflingEpoch = obsHelper.newValue(EpochNumber.ZERO); - private ObsValue currentShufflingEpoch = obsHelper.newValue(EpochNumber.ZERO); - private ObsValue previousShufflingSeed = obsHelper.newValue(Hash32.ZERO); - private ObsValue currentShufflingSeed = obsHelper.newValue(Hash32.ZERO); + private ObsValue latestStartShard = obsHelper.newValue(ShardNumber.ZERO); /* Finality */ @@ -87,7 +82,7 @@ public class BeaconStateImpl implements MutableBeaconState { /* PoW receipt root */ private ObsValue latestEth1Data = obsHelper.newValue(Eth1Data.EMPTY); - private ObsValue> eth1DataVotes = + private ObsValue> eth1DataVotes = obsHelper.newValue(ObservableListImpl.create(Integer::valueOf)); private ObsValue depositIndex = obsHelper.newValue(UInt64.ZERO); @@ -99,16 +94,10 @@ public BeaconStateImpl() {} fork.set(state.getFork()); validatorRegistry.set(state.getValidatorRegistry().createMutableCopy()); - validatorBalances.set(state.getValidatorBalances().createMutableCopy()); - validatorRegistryUpdateEpoch.set(state.getValidatorRegistryUpdateEpoch()); + balances.set(state.getBalances().createMutableCopy()); latestRandaoMixes.set(state.getLatestRandaoMixes().createMutableCopy()); - previousShufflingStartShard.set(state.getPreviousShufflingStartShard()); - currentShufflingStartShard.set(state.getCurrentShufflingStartShard()); - previousShufflingEpoch.set(state.getPreviousShufflingEpoch()); - currentShufflingEpoch.set(state.getCurrentShufflingEpoch()); - previousShufflingSeed.set(state.getPreviousShufflingSeed()); - currentShufflingSeed.set(state.getCurrentShufflingSeed()); + latestStartShard.set(state.getLatestStartShard()); previousEpochAttestations.set(state.getPreviousEpochAttestations().createMutableCopy()); currentEpochAttestations.set(state.getCurrentEpochAttestations().createMutableCopy()); @@ -192,24 +181,13 @@ public void setValidatorRegistry( } @Override - public WriteList getValidatorBalances() { - return validatorBalances.get(); + public WriteList getBalances() { + return balances.get(); } - public void setValidatorBalances( - WriteList validatorBalances) { - this.validatorBalances.set(validatorBalances); - } - - @Override - public EpochNumber getValidatorRegistryUpdateEpoch() { - return validatorRegistryUpdateEpoch.get(); - } - - @Override - public void setValidatorRegistryUpdateEpoch( - EpochNumber validatorRegistryUpdateEpoch) { - this.validatorRegistryUpdateEpoch.set(validatorRegistryUpdateEpoch); + public void setBalances( + WriteList balances) { + this.balances.set(balances); } @Override @@ -223,65 +201,13 @@ public void setLatestRandaoMixes( } @Override - public ShardNumber getPreviousShufflingStartShard() { - return previousShufflingStartShard.get(); - } - - @Override - public void setPreviousShufflingStartShard( - ShardNumber previousShufflingStartShard) { - this.previousShufflingStartShard.set(previousShufflingStartShard); - } - - @Override - public ShardNumber getCurrentShufflingStartShard() { - return currentShufflingStartShard.get(); - } - - @Override - public void setCurrentShufflingStartShard( - ShardNumber currentShufflingStartShard) { - this.currentShufflingStartShard.set(currentShufflingStartShard); - } - - @Override - public EpochNumber getPreviousShufflingEpoch() { - return previousShufflingEpoch.get(); - } - - @Override - public void setPreviousShufflingEpoch(EpochNumber previousShufflingEpoch) { - this.previousShufflingEpoch.set(previousShufflingEpoch); - } - - @Override - public EpochNumber getCurrentShufflingEpoch() { - return currentShufflingEpoch.get(); - } - - @Override - public void setCurrentShufflingEpoch(EpochNumber currentShufflingEpoch) { - this.currentShufflingEpoch.set(currentShufflingEpoch); - } - - @Override - public Hash32 getPreviousShufflingSeed() { - return previousShufflingSeed.get(); - } - - @Override - public void setPreviousShufflingSeed(Hash32 previousShufflingSeed) { - this.previousShufflingSeed.set(previousShufflingSeed); - } - - @Override - public Hash32 getCurrentShufflingSeed() { - return currentShufflingSeed.get(); + public ShardNumber getLatestStartShard() { + return latestStartShard.get(); } @Override - public void setCurrentShufflingSeed(Hash32 currentShufflingSeed) { - this.currentShufflingSeed.set(currentShufflingSeed); + public void setLatestStartShard(ShardNumber latestStartShard) { + this.latestStartShard.set(latestStartShard); } public WriteList getPreviousEpochAttestations() { @@ -462,12 +388,12 @@ public void setLatestEth1Data(Eth1Data latestEth1Data) { } @Override - public WriteList getEth1DataVotes() { + public WriteList getEth1DataVotes() { return eth1DataVotes.get(); } public void setEth1DataVotes( - WriteList eth1DataVotes) { + WriteList eth1DataVotes) { this.eth1DataVotes.set(eth1DataVotes); } diff --git a/core/src/main/java/org/ethereum/beacon/core/state/Eth1Data.java b/core/src/main/java/org/ethereum/beacon/core/state/Eth1Data.java index 32bcfea6d..7697834e7 100644 --- a/core/src/main/java/org/ethereum/beacon/core/state/Eth1Data.java +++ b/core/src/main/java/org/ethereum/beacon/core/state/Eth1Data.java @@ -1,30 +1,35 @@ package org.ethereum.beacon.core.state; +import com.google.common.base.MoreObjects; import com.google.common.base.Objects; import org.ethereum.beacon.core.BeaconState; import org.ethereum.beacon.ssz.annotation.SSZ; import org.ethereum.beacon.ssz.annotation.SSZSerializable; import tech.pegasys.artemis.ethereum.core.Hash32; +import tech.pegasys.artemis.util.uint.UInt64; /** * Keeps eth1 data. * * @see BeaconState * @see Eth1Data + * href="https://github.com/ethereum/eth2.0-specs/blob/blob/v0.6.1/specs/core/0_beacon-chain.md#eth1data">Eth1Data * in the spec. */ @SSZSerializable public class Eth1Data { - public static final Eth1Data EMPTY = new Eth1Data(Hash32.ZERO, Hash32.ZERO); + public static final Eth1Data EMPTY = new Eth1Data(Hash32.ZERO, UInt64.ZERO, Hash32.ZERO); /** Root of the deposit tree. */ @SSZ private final Hash32 depositRoot; + /** Total number of deposits. */ + @SSZ private final UInt64 depositCount; /** Hash of eth1 block which {@code depositRoot} relates to. */ @SSZ private final Hash32 blockHash; - public Eth1Data(Hash32 depositRoot, Hash32 blockHash) { + public Eth1Data(Hash32 depositRoot, UInt64 depositCount, Hash32 blockHash) { this.depositRoot = depositRoot; + this.depositCount = depositCount; this.blockHash = blockHash; } @@ -32,6 +37,10 @@ public Hash32 getDepositRoot() { return depositRoot; } + public UInt64 getDepositCount() { + return depositCount; + } + public Hash32 getBlockHash() { return blockHash; } @@ -46,11 +55,21 @@ public boolean equals(Object o) { } Eth1Data eth1Data = (Eth1Data) o; return Objects.equal(depositRoot, eth1Data.depositRoot) + && Objects.equal(depositCount, eth1Data.depositCount) && Objects.equal(blockHash, eth1Data.blockHash); } + @Override + public int hashCode() { + return Objects.hashCode(depositRoot, depositCount, blockHash); + } + @Override public String toString() { - return "Eth1Data[deposit=" + depositRoot.toStringShort() + ", block=" + blockHash.toStringShort() + "]"; + return MoreObjects.toStringHelper(this) + .add("depositRoot", depositRoot.toStringShort()) + .add("depositCount", depositCount) + .add("block", blockHash.toStringShort()) + .toString(); } } diff --git a/core/src/main/java/org/ethereum/beacon/core/state/Fork.java b/core/src/main/java/org/ethereum/beacon/core/state/Fork.java index 6d6c87015..e24c8b05b 100644 --- a/core/src/main/java/org/ethereum/beacon/core/state/Fork.java +++ b/core/src/main/java/org/ethereum/beacon/core/state/Fork.java @@ -14,7 +14,7 @@ * * @see BeaconState * @see Fork + * href="https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#fork">Fork * in the spec */ @SSZSerializable diff --git a/core/src/main/java/org/ethereum/beacon/core/state/HistoricalBatch.java b/core/src/main/java/org/ethereum/beacon/core/state/HistoricalBatch.java index a794be073..727dbfae8 100644 --- a/core/src/main/java/org/ethereum/beacon/core/state/HistoricalBatch.java +++ b/core/src/main/java/org/ethereum/beacon/core/state/HistoricalBatch.java @@ -1,35 +1,38 @@ package org.ethereum.beacon.core.state; -import java.util.List; +import org.ethereum.beacon.core.types.SlotNumber; import org.ethereum.beacon.ssz.annotation.SSZ; import org.ethereum.beacon.ssz.annotation.SSZSerializable; import tech.pegasys.artemis.ethereum.core.Hash32; +import tech.pegasys.artemis.util.collections.ReadVector; /** * A batch of historical data. * * @see HistoricalBatch + * href="https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#historicalbatch">HistoricalBatch * in the spec. */ @SSZSerializable public class HistoricalBatch { /** Block roots. */ - @SSZ private final List blockRoots; + @SSZ(vectorLengthVar = "spec.SLOTS_PER_HISTORICAL_ROOT") + private final ReadVector blockRoots;; /** State roots. */ - @SSZ private final List stateRoots; + @SSZ(vectorLengthVar = "spec.SLOTS_PER_HISTORICAL_ROOT") + private final ReadVector stateRoots;; - public HistoricalBatch(List blockRoots, List stateRoots) { + public HistoricalBatch(ReadVector blockRoots, ReadVector stateRoots) { this.blockRoots = blockRoots; this.stateRoots = stateRoots; } - public List getBlockRoots() { + public ReadVector getBlockRoots() { return blockRoots; } - public List getStateRoots() { + public ReadVector getStateRoots() { return stateRoots; } } diff --git a/core/src/main/java/org/ethereum/beacon/core/state/PendingAttestation.java b/core/src/main/java/org/ethereum/beacon/core/state/PendingAttestation.java index a4e022baf..5353780f0 100644 --- a/core/src/main/java/org/ethereum/beacon/core/state/PendingAttestation.java +++ b/core/src/main/java/org/ethereum/beacon/core/state/PendingAttestation.java @@ -9,6 +9,7 @@ import org.ethereum.beacon.core.types.Bitfield; import org.ethereum.beacon.core.types.SlotNumber; import org.ethereum.beacon.core.types.Time; +import org.ethereum.beacon.core.types.ValidatorIndex; import org.ethereum.beacon.ssz.annotation.SSZ; import org.ethereum.beacon.ssz.annotation.SSZSerializable; @@ -17,28 +18,30 @@ * * @see BeaconState * @see PendingAttestation + * href="https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#pendingattestation">PendingAttestation * in the spec */ @SSZSerializable public class PendingAttestation { - /** Proof of custody bitfield. */ + /** Attester aggregation bitfield. */ @SSZ private final Bitfield aggregationBitfield; /** Signed data. */ @SSZ private final AttestationData data; - /** Attester participation bitfield. */ - @SSZ private final Bitfield custodyBitfield; /** Slot in which it was included. */ - @SSZ private final SlotNumber inclusionSlot; + @SSZ private final SlotNumber inclusionDelay; + /** Proposer index. */ + @SSZ private final ValidatorIndex proposerIndex; - public PendingAttestation(Bitfield aggregationBitfield, - AttestationData data, Bitfield custodyBitfield, - SlotNumber inclusionSlot) { + public PendingAttestation( + Bitfield aggregationBitfield, + AttestationData data, + SlotNumber inclusionDelay, + ValidatorIndex proposerIndex) { this.aggregationBitfield = aggregationBitfield; this.data = data; - this.custodyBitfield = custodyBitfield; - this.inclusionSlot = inclusionSlot; + this.inclusionDelay = inclusionDelay; + this.proposerIndex = proposerIndex; } public Bitfield getAggregationBitfield() { @@ -49,12 +52,12 @@ public AttestationData getData() { return data; } - public Bitfield getCustodyBitfield() { - return custodyBitfield; + public ValidatorIndex getProposerIndex() { + return proposerIndex; } - public SlotNumber getInclusionSlot() { - return inclusionSlot; + public SlotNumber getInclusionDelay() { + return inclusionDelay; } @Override @@ -64,8 +67,8 @@ public boolean equals(Object o) { PendingAttestation that = (PendingAttestation) o; return Objects.equal(data, that.data) && Objects.equal(aggregationBitfield, that.aggregationBitfield) - && Objects.equal(custodyBitfield, that.custodyBitfield) - && Objects.equal(inclusionSlot, that.inclusionSlot); + && Objects.equal(proposerIndex, that.proposerIndex) + && Objects.equal(inclusionDelay, that.inclusionDelay); } private String getSignerIndices() { @@ -81,15 +84,15 @@ public String toString(@Nullable SpecConstants spec,@Nullable Time beaconStart) return "Attestation[" + data.toString(spec, beaconStart) + ", attesters=" + getSignerIndices() - + ", cusodyBits=" + custodyBitfield - + ", inclusionSlot=#" + getInclusionSlot().toStringNumber(spec) + + ", proposerIndex=" + getProposerIndex() + + ", inclusionDelay=#" + getInclusionDelay().toStringNumber(spec) + "]"; } public String toStringShort(@Nullable SpecConstants spec) { - return "#" + getData().getSlot().toStringNumber(spec) + "/" - + "#" + getInclusionSlot().toStringNumber(spec) + "/" - + getData().getShard().toString(spec) + "/" + return "epoch=" + getData().getTargetEpoch().toString(spec) + "/" + + "delay=" + getInclusionDelay().toStringNumber(spec) + "/" + + getData().getShard().toString() + "/" + getData().getBeaconBlockRoot().toStringShort() + "/" + getSignerIndices(); } diff --git a/core/src/main/java/org/ethereum/beacon/core/state/ValidatorRecord.java b/core/src/main/java/org/ethereum/beacon/core/state/ValidatorRecord.java index 2232d8db7..b9f06ec9b 100644 --- a/core/src/main/java/org/ethereum/beacon/core/state/ValidatorRecord.java +++ b/core/src/main/java/org/ethereum/beacon/core/state/ValidatorRecord.java @@ -2,9 +2,10 @@ import com.google.common.base.Objects; import org.ethereum.beacon.core.BeaconState; -import org.ethereum.beacon.core.operations.deposit.DepositInput; +import org.ethereum.beacon.core.operations.deposit.DepositData; import org.ethereum.beacon.core.types.BLSPubkey; import org.ethereum.beacon.core.types.EpochNumber; +import org.ethereum.beacon.core.types.Gwei; import org.ethereum.beacon.ssz.annotation.SSZ; import org.ethereum.beacon.ssz.annotation.SSZSerializable; import tech.pegasys.artemis.ethereum.core.Hash32; @@ -14,7 +15,7 @@ * * @see BeaconState * @see Validator + * href="https://github.com/ethereum/eth2.0-specs/blob/v0.6.1/specs/core/0_beacon-chain.md#validator">Validator * in the spec */ @SSZSerializable @@ -24,32 +25,36 @@ public class ValidatorRecord { @SSZ private final BLSPubkey pubKey; /** Withdrawal credentials. */ @SSZ private final Hash32 withdrawalCredentials; + /** Epoch when became eligible for activation. */ + @SSZ private final EpochNumber activationEligibilityEpoch; /** Slot when validator activated */ @SSZ private final EpochNumber activationEpoch; /** Slot when validator exited */ @SSZ private final EpochNumber exitEpoch; /** Epoch when validator is eligible to withdraw */ @SSZ private final EpochNumber withdrawableEpoch; - /** Did the validator initiate an exit */ - @SSZ private final Boolean initiatedExit; /** Status flags. */ @SSZ private final Boolean slashed; + /** Effective balance. */ + @SSZ private final Gwei effectiveBalance; public ValidatorRecord( BLSPubkey pubKey, Hash32 withdrawalCredentials, + EpochNumber activationEligibilityEpoch, EpochNumber activationEpoch, EpochNumber exitEpoch, EpochNumber withdrawableEpoch, - Boolean initiatedExit, - Boolean slashed) { + Boolean slashed, + Gwei effectiveBalance) { this.pubKey = pubKey; this.withdrawalCredentials = withdrawalCredentials; + this.activationEligibilityEpoch = activationEligibilityEpoch; this.activationEpoch = activationEpoch; this.exitEpoch = exitEpoch; this.withdrawableEpoch = withdrawableEpoch; - this.initiatedExit = initiatedExit; this.slashed = slashed; + this.effectiveBalance = effectiveBalance; } public BLSPubkey getPubKey() { @@ -60,6 +65,10 @@ public Hash32 getWithdrawalCredentials() { return withdrawalCredentials; } + public EpochNumber getActivationEligibilityEpoch() { + return activationEligibilityEpoch; + } + public EpochNumber getActivationEpoch() { return activationEpoch; } @@ -72,14 +81,14 @@ public EpochNumber getWithdrawableEpoch() { return withdrawableEpoch; } - public Boolean getInitiatedExit() { - return initiatedExit; - } - public Boolean getSlashed() { return slashed; } + public Gwei getEffectiveBalance() { + return effectiveBalance; + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -88,10 +97,11 @@ public boolean equals(Object o) { return Objects.equal(pubKey, that.pubKey) && Objects.equal(withdrawalCredentials, that.withdrawalCredentials) && Objects.equal(activationEpoch, that.activationEpoch) + && Objects.equal(activationEligibilityEpoch, that.activationEligibilityEpoch) && Objects.equal(exitEpoch, that.exitEpoch) && Objects.equal(withdrawableEpoch, that.withdrawableEpoch) - && Objects.equal(initiatedExit, that.initiatedExit) - && Objects.equal(slashed, that.slashed); + && Objects.equal(slashed, that.slashed) + && Objects.equal(effectiveBalance, that.effectiveBalance); } public Builder builder() { @@ -107,14 +117,16 @@ public String toString() { + withdrawalCredentials + ", activationEpoch=" + activationEpoch + + ", activationEligibilityEpoch=" + + activationEligibilityEpoch + ", exitEpoch=" + exitEpoch + ", withdrawableEpoch=" + withdrawableEpoch - + ", initiatedExit=" - + initiatedExit + ", slashed=" + slashed + + ", effectiveBalance=" + + effectiveBalance + '}'; } @@ -123,10 +135,11 @@ public static class Builder { private BLSPubkey pubKey; private Hash32 withdrawalCredentials; private EpochNumber activationEpoch; + private EpochNumber activationEligibilityEpoch; private EpochNumber exitEpoch; private EpochNumber withdrawableEpoch; - private Boolean initiatedExit; private Boolean slashed; + private Gwei effectiveBalance; private Builder() {} @@ -134,11 +147,11 @@ public static Builder createEmpty() { return new Builder(); } - public static Builder fromDepositInput(DepositInput input) { + public static Builder fromDepositData(DepositData data) { Builder builder = new Builder(); - builder.pubKey = input.getPubKey(); - builder.withdrawalCredentials = input.getWithdrawalCredentials(); + builder.pubKey = data.getPubKey(); + builder.withdrawalCredentials = data.getWithdrawalCredentials(); return builder; } @@ -149,10 +162,11 @@ public static Builder fromRecord(ValidatorRecord record) { builder.pubKey = record.pubKey; builder.withdrawalCredentials = record.withdrawalCredentials; builder.activationEpoch = record.activationEpoch; + builder.activationEligibilityEpoch = record.activationEligibilityEpoch; builder.exitEpoch = record.exitEpoch; builder.withdrawableEpoch = record.withdrawableEpoch; - builder.initiatedExit = record.initiatedExit; builder.slashed = record.slashed; + builder.effectiveBalance = record.effectiveBalance; return builder; } @@ -161,19 +175,21 @@ public ValidatorRecord build() { assert pubKey != null; assert withdrawalCredentials != null; assert activationEpoch != null; + assert activationEligibilityEpoch != null; assert exitEpoch != null; assert withdrawableEpoch != null; - assert initiatedExit != null; assert slashed != null; + assert effectiveBalance != null; return new ValidatorRecord( pubKey, withdrawalCredentials, activationEpoch, + activationEligibilityEpoch, exitEpoch, withdrawableEpoch, - initiatedExit, - slashed); + slashed, + effectiveBalance); } public Builder withPubKey(BLSPubkey pubKey) { @@ -191,6 +207,11 @@ public Builder withActivationEpoch(EpochNumber activationEpoch) { return this; } + public Builder withActivationEligibilityEpoch(EpochNumber activationEligibilityEpoch) { + this.activationEligibilityEpoch = activationEligibilityEpoch; + return this; + } + public Builder withExitEpoch(EpochNumber exitEpoch) { this.exitEpoch = exitEpoch; return this; @@ -201,13 +222,13 @@ public Builder withWithdrawableEpoch(EpochNumber withdrawableEpoch) { return this; } - public Builder withInitiatedExit(Boolean initiatedExit) { - this.initiatedExit = initiatedExit; + public Builder withSlashed(Boolean slashed) { + this.slashed = slashed; return this; } - public Builder withSlashed(Boolean slashed) { - this.slashed = slashed; + public Builder withEffectiveBalance(Gwei effectiveBalance) { + this.effectiveBalance = effectiveBalance; return this; } } diff --git a/core/src/main/java/org/ethereum/beacon/core/types/EpochNumber.java b/core/src/main/java/org/ethereum/beacon/core/types/EpochNumber.java index 26a623718..30c5fd7df 100644 --- a/core/src/main/java/org/ethereum/beacon/core/types/EpochNumber.java +++ b/core/src/main/java/org/ethereum/beacon/core/types/EpochNumber.java @@ -33,6 +33,14 @@ public EpochNumber plus(long unsignedAddend) { return new EpochNumber(super.plus(unsignedAddend)); } + public EpochNumber plusModulo(long addend, EpochNumber divisor) { + return plusModulo(UInt64.valueOf(addend), divisor); + } + + public EpochNumber plusModulo(UInt64 addend, EpochNumber divisor) { + return new EpochNumber(this.plus(addend).modulo(divisor)); + } + public EpochNumber minus(EpochNumber subtract) { return new EpochNumber(super.minus(subtract)); } diff --git a/core/src/main/java/org/ethereum/beacon/core/types/Gwei.java b/core/src/main/java/org/ethereum/beacon/core/types/Gwei.java index 6fa5e311b..46ed49a02 100644 --- a/core/src/main/java/org/ethereum/beacon/core/types/Gwei.java +++ b/core/src/main/java/org/ethereum/beacon/core/types/Gwei.java @@ -33,35 +33,6 @@ public Gwei minus(Gwei subtrahend) { return new Gwei(super.minus(subtrahend)); } - /** - * Saturation subtraction. - * - * @param subtrahend A Gwei representing an unsigned long to subtract. - * @return {@link #MIN_VALUE} if underflowed, otherwise, result of {@link #minus(UInt64)}. - */ - public Gwei minusSat(Gwei subtrahend) { - if (this.compareTo(subtrahend) < 0) { - return Gwei.castFrom(MIN_VALUE); - } else { - return minus(subtrahend); - } - } - - /** - * Saturation addition. - * - * @param addend A Gwei representing an unsigned long to add. - * @return {@link #MAX_VALUE} if overflowed, otherwise, result of {@link #plus(UInt64)}. - */ - public Gwei plusSat(Gwei addend) { - Gwei res = this.plus(addend); - if (res.compareTo(this) <= 0 && addend.compareTo(Gwei.ZERO) > 0) { - return Gwei.castFrom(MAX_VALUE); - } else { - return res; - } - } - @Override public Gwei times(UInt64 unsignedMultiplier) { return new Gwei(super.times(unsignedMultiplier)); diff --git a/core/src/main/java/org/ethereum/beacon/core/types/ShardNumber.java b/core/src/main/java/org/ethereum/beacon/core/types/ShardNumber.java index 716ecc4f1..bb2d541d2 100644 --- a/core/src/main/java/org/ethereum/beacon/core/types/ShardNumber.java +++ b/core/src/main/java/org/ethereum/beacon/core/types/ShardNumber.java @@ -41,6 +41,14 @@ public ShardNumber plusModulo(UInt64 addend, ShardNumber divisor) { return new ShardNumber(this.plus(addend).modulo(divisor)); } + public ShardNumber minusModulo(long subtrahend, ShardNumber divisor) { + return minusModulo(UInt64.valueOf(subtrahend), divisor); + } + + public ShardNumber minusModulo(UInt64 subtrahend, ShardNumber divisor) { + return new ShardNumber(this.minus(subtrahend).modulo(divisor)); + } + public ShardNumber safeModulo(Function safeCalc, ShardNumber divisor) { return new ShardNumber(safeCalc.apply(this).modulo(divisor)); } @@ -59,14 +67,4 @@ public ShardNumber decrement() { public ShardNumber zeroElement() { return ZERO; } - - @Override - public String toString() { - return toString(null); - } - - public String toString(@Nullable SpecConstants spec) { - return spec == null ? super.toString() : - spec.getBeaconChainShardNumber().equals(this) ? "Beacon" : super.toString(); - } } \ No newline at end of file diff --git a/core/src/main/java/org/ethereum/beacon/core/types/SlotNumber.java b/core/src/main/java/org/ethereum/beacon/core/types/SlotNumber.java index bcb2fe156..f38232f39 100644 --- a/core/src/main/java/org/ethereum/beacon/core/types/SlotNumber.java +++ b/core/src/main/java/org/ethereum/beacon/core/types/SlotNumber.java @@ -56,8 +56,18 @@ public SlotNumber minus(long unsignedAddend) { } @Override - public SlotNumber minus(UInt64 addend) { - return new SlotNumber(super.minus(addend)); + public SlotNumber minus(UInt64 subtrahend) { + return new SlotNumber(super.minus(subtrahend)); + } + + @Override + public SlotNumber minusSat(UInt64 subtrahend) { + return new SlotNumber(super.minusSat(subtrahend)); + } + + @Override + public SlotNumber minusSat(long subtrahend) { + return new SlotNumber(super.minusSat(subtrahend)); } @Override diff --git a/core/src/test/java/org/ethereum/beacon/core/ModelsSerializeTest.java b/core/src/test/java/org/ethereum/beacon/core/ModelsSerializeTest.java index e72778a49..40dd2975c 100644 --- a/core/src/test/java/org/ethereum/beacon/core/ModelsSerializeTest.java +++ b/core/src/test/java/org/ethereum/beacon/core/ModelsSerializeTest.java @@ -7,6 +7,7 @@ import java.util.Collections; import java.util.List; import java.util.Random; +import org.ethereum.beacon.consensus.BeaconChainSpec; import org.ethereum.beacon.consensus.BeaconStateEx; import org.ethereum.beacon.consensus.transition.BeaconStateExImpl; import org.ethereum.beacon.core.operations.Attestation; @@ -17,9 +18,8 @@ import org.ethereum.beacon.core.operations.attestation.AttestationData; import org.ethereum.beacon.core.operations.attestation.Crosslink; import org.ethereum.beacon.core.operations.deposit.DepositData; -import org.ethereum.beacon.core.operations.deposit.DepositInput; import org.ethereum.beacon.core.operations.slashing.AttesterSlashing; -import org.ethereum.beacon.core.operations.slashing.SlashableAttestation; +import org.ethereum.beacon.core.operations.slashing.IndexedAttestation; import org.ethereum.beacon.core.spec.SpecConstants; import org.ethereum.beacon.core.spec.SpecConstantsResolver; import org.ethereum.beacon.core.state.BeaconStateImpl; @@ -35,7 +35,6 @@ import org.ethereum.beacon.core.types.Gwei; import org.ethereum.beacon.core.types.ShardNumber; import org.ethereum.beacon.core.types.SlotNumber; -import org.ethereum.beacon.core.types.Time; import org.ethereum.beacon.core.types.ValidatorIndex; import org.ethereum.beacon.core.util.BeaconBlockTestUtil; import org.ethereum.beacon.crypto.Hashes; @@ -44,31 +43,35 @@ import org.junit.Before; import org.junit.Test; import tech.pegasys.artemis.ethereum.core.Hash32; +import tech.pegasys.artemis.util.bytes.Bytes32; import tech.pegasys.artemis.util.bytes.Bytes48; import tech.pegasys.artemis.util.bytes.Bytes96; import tech.pegasys.artemis.util.bytes.BytesValue; +import tech.pegasys.artemis.util.collections.ReadVector; import tech.pegasys.artemis.util.uint.UInt64; public class ModelsSerializeTest { private SSZSerializer sszSerializer; + private SpecConstants specConstants; @Before public void setup() { + specConstants = BeaconChainSpec.DEFAULT_CONSTANTS; sszSerializer = new SSZBuilder() - .withExternalVarResolver(new SpecConstantsResolver(new SpecConstants() {})) + .withExternalVarResolver(new SpecConstantsResolver(specConstants)) .buildSerializer(); } private AttestationData createAttestationData() { AttestationData expected = new AttestationData( - SlotNumber.of(123), - Hashes.keccak256(BytesValue.fromHexString("aa")), + Hashes.sha256(BytesValue.fromHexString("aa")), EpochNumber.ZERO, - Hashes.keccak256(BytesValue.fromHexString("bb")), - Hashes.keccak256(BytesValue.fromHexString("cc")), + Hashes.sha256(BytesValue.fromHexString("bb")), + EpochNumber.of(123), + Hashes.sha256(BytesValue.fromHexString("cc")), ShardNumber.of(345), - new Crosslink(EpochNumber.ZERO, Hashes.keccak256(BytesValue.fromHexString("dd"))), + Hashes.sha256(BytesValue.fromHexString("dd")), Hash32.ZERO); return expected; @@ -102,27 +105,12 @@ public void attestationTest() { assertEquals(expected, reconstructed); } - private DepositInput createDepositInput() { - DepositInput depositInput = - new DepositInput( - BLSPubkey.wrap(Bytes48.TRUE), - Hashes.keccak256(BytesValue.fromHexString("aa")), - BLSSignature.wrap(Bytes96.ZERO)); - - return depositInput; - } - - @Test - public void depositInputTest() { - DepositInput expected = createDepositInput(); - BytesValue encoded = sszSerializer.encode2(expected); - DepositInput reconstructed = sszSerializer.decode(encoded, DepositInput.class); - assertEquals(expected, reconstructed); - } - private DepositData createDepositData() { DepositData depositData = - new DepositData(Gwei.ZERO, Time.castFrom(UInt64.valueOf(123)), createDepositInput()); + new DepositData( + BLSPubkey.wrap(Bytes48.TRUE), + Hashes.sha256(BytesValue.fromHexString("aa")), + Gwei.ZERO, BLSSignature.wrap(Bytes96.ZERO)); return depositData; } @@ -136,16 +124,21 @@ public void depositDataTest() { } private Deposit createDeposit1() { - Deposit deposit = new Deposit(Collections.emptyList(), UInt64.ZERO, createDepositData()); + Deposit deposit = new Deposit( + ReadVector.wrap( + Collections.nCopies(specConstants.getDepositContractTreeDepth().getIntValue(), Hash32.ZERO), Integer::new), + UInt64.ZERO, createDepositData()); return deposit; } private Deposit createDeposit2() { ArrayList hashes = new ArrayList<>(); - hashes.add(Hashes.keccak256(BytesValue.fromHexString("aa"))); - hashes.add(Hashes.keccak256(BytesValue.fromHexString("bb"))); - Deposit deposit = new Deposit(hashes, UInt64.ZERO, createDepositData()); + hashes.add(Hashes.sha256(BytesValue.fromHexString("aa"))); + hashes.add(Hashes.sha256(BytesValue.fromHexString("bb"))); + hashes.addAll(Collections.nCopies(specConstants.getDepositContractTreeDepth().getIntValue() - hashes.size(), Hash32.ZERO)); + ReadVector proof = ReadVector.wrap(hashes, Integer::new); + Deposit deposit = new Deposit(proof, UInt64.ZERO, createDepositData()); return deposit; } @@ -220,9 +213,10 @@ private BeaconBlockBody createBeaconBlockBody() { voluntaryExits.add(createExit()); List transfers = new ArrayList<>(); BeaconBlockBody beaconBlockBody = - new BeaconBlockBody( + BeaconBlockBody.create( BLSSignature.ZERO, - new Eth1Data(Hash32.ZERO, Hash32.ZERO), + new Eth1Data(Hash32.ZERO, UInt64.ZERO, Hash32.ZERO), + Bytes32.ZERO, proposerSlashings, attesterSlashings, attestations, @@ -240,19 +234,19 @@ private AttesterSlashing createAttesterSlashings() { createSlashableAttestation()); } - private SlashableAttestation createSlashableAttestation() { - return new SlashableAttestation( - Arrays.asList(ValidatorIndex.of(234), ValidatorIndex.of(678)), + private IndexedAttestation createSlashableAttestation() { + return new IndexedAttestation( + Arrays.asList(ValidatorIndex.of(234), ValidatorIndex.of(235)), + Arrays.asList(ValidatorIndex.of(678), ValidatorIndex.of(679)), createAttestationData(), - Bitfield.of(BytesValue.fromHexString("aa19")), BLSSignature.wrap(Bytes96.fromHexString("aa"))); } @Test public void slashableAttestationTest() { - SlashableAttestation expected = createSlashableAttestation(); + IndexedAttestation expected = createSlashableAttestation(); BytesValue encoded = sszSerializer.encode2(expected); - SlashableAttestation reconstructed = sszSerializer.decode(encoded, SlashableAttestation.class); + IndexedAttestation reconstructed = sszSerializer.decode(encoded, IndexedAttestation.class); assertEquals(expected, reconstructed); } @@ -276,8 +270,8 @@ private BeaconBlock createBeaconBlock() { BeaconBlock beaconBlock = new BeaconBlock( SlotNumber.castFrom(UInt64.MAX_VALUE), - Hashes.keccak256(BytesValue.fromHexString("aa")), - Hashes.keccak256(BytesValue.fromHexString("bb")), + Hashes.sha256(BytesValue.fromHexString("aa")), + Hashes.sha256(BytesValue.fromHexString("bb")), createBeaconBlockBody(), BLSSignature.wrap(Bytes96.fromHexString("aa"))); @@ -362,8 +356,8 @@ private PendingAttestation createPendingAttestation() { new PendingAttestation( Bitfield.of(BytesValue.fromHexString("aa")), createAttestationData(), - Bitfield.of(BytesValue.fromHexString("bb")), - SlotNumber.ZERO); + SlotNumber.ZERO, + ValidatorIndex.ZERO); return pendingAttestation; } @@ -379,15 +373,15 @@ public void pendingAttestationTest() { private ValidatorRecord createValidatorRecord() { ValidatorRecord validatorRecord = - ValidatorRecord.Builder.fromDepositInput(createDepositInput()) + ValidatorRecord.Builder.fromDepositData(createDepositData()) .withPubKey(BLSPubkey.ZERO) .withWithdrawalCredentials(Hash32.ZERO) + .withActivationEligibilityEpoch(EpochNumber.ZERO) .withActivationEpoch(EpochNumber.ZERO) .withExitEpoch(EpochNumber.ZERO) .withWithdrawableEpoch(EpochNumber.ZERO) - .withInitiatedExit(Boolean.FALSE) - .withExitEpoch(EpochNumber.ZERO) .withSlashed(Boolean.FALSE) + .withEffectiveBalance(Gwei.ZERO) .build(); return validatorRecord; diff --git a/core/src/test/java/org/ethereum/beacon/core/SSZSerializableAnnotationTest.java b/core/src/test/java/org/ethereum/beacon/core/SSZSerializableAnnotationTest.java index e7d81e20f..80232d4b5 100644 --- a/core/src/test/java/org/ethereum/beacon/core/SSZSerializableAnnotationTest.java +++ b/core/src/test/java/org/ethereum/beacon/core/SSZSerializableAnnotationTest.java @@ -17,9 +17,8 @@ import org.ethereum.beacon.core.operations.attestation.AttestationData; import org.ethereum.beacon.core.operations.attestation.AttestationDataAndCustodyBit; import org.ethereum.beacon.core.operations.deposit.DepositData; -import org.ethereum.beacon.core.operations.deposit.DepositInput; import org.ethereum.beacon.core.operations.slashing.AttesterSlashing; -import org.ethereum.beacon.core.operations.slashing.SlashableAttestation; +import org.ethereum.beacon.core.operations.slashing.IndexedAttestation; import org.ethereum.beacon.core.state.BeaconStateImpl; import org.ethereum.beacon.core.operations.attestation.Crosslink; import org.ethereum.beacon.core.state.Eth1Data; @@ -124,7 +123,6 @@ public void testAnnotatedClassesHaveTests() throws Exception { BeaconStateImpl.class, Deposit.class, DepositData.class, - DepositInput.class, VoluntaryExit.class, ProposerSlashing.class, Crosslink.class, @@ -139,7 +137,7 @@ public void testAnnotatedClassesHaveTests() throws Exception { BLSSignature.class, EpochNumber.class, Gwei.class, - SlashableAttestation.class, + IndexedAttestation.class, ShardNumber.class, SlotNumber.class, Time.class, diff --git a/core/src/test/java/org/ethereum/beacon/core/util/AttestationTestUtil.java b/core/src/test/java/org/ethereum/beacon/core/util/AttestationTestUtil.java index 8a6e500b2..d1255e572 100644 --- a/core/src/test/java/org/ethereum/beacon/core/util/AttestationTestUtil.java +++ b/core/src/test/java/org/ethereum/beacon/core/util/AttestationTestUtil.java @@ -12,6 +12,7 @@ import org.ethereum.beacon.core.types.BLSSignature; import org.ethereum.beacon.core.types.Bitfield; import org.ethereum.beacon.core.types.EpochNumber; +import org.ethereum.beacon.core.types.ShardNumber; import tech.pegasys.artemis.ethereum.core.Hash32; import tech.pegasys.artemis.util.bytes.Bytes96; import tech.pegasys.artemis.util.bytes.BytesValue; @@ -35,13 +36,13 @@ public static Attestation createRandomAttestation(Random random) { public static AttestationData createRandomAttestationData(Random random) { return new AttestationData( - SpecConstants.GENESIS_SLOT, Hash32.random(random), BeaconChainSpec.DEFAULT_CONSTANTS.getGenesisEpoch(), Hash32.random(random), + BeaconChainSpec.DEFAULT_CONSTANTS.getGenesisEpoch().increment(), + Hash32.random(random), + ShardNumber.ZERO, Hash32.random(random), - SpecConstants.BEACON_CHAIN_SHARD_NUMBER, - new Crosslink(EpochNumber.ZERO, Hash32.random(random)), Hash32.random(random)); } } diff --git a/core/src/test/java/org/ethereum/beacon/core/util/AttesterSlashingTestUtil.java b/core/src/test/java/org/ethereum/beacon/core/util/AttesterSlashingTestUtil.java index 03cc6760e..1bf628900 100644 --- a/core/src/test/java/org/ethereum/beacon/core/util/AttesterSlashingTestUtil.java +++ b/core/src/test/java/org/ethereum/beacon/core/util/AttesterSlashingTestUtil.java @@ -6,7 +6,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import org.ethereum.beacon.core.operations.slashing.AttesterSlashing; -import org.ethereum.beacon.core.operations.slashing.SlashableAttestation; +import org.ethereum.beacon.core.operations.slashing.IndexedAttestation; import org.ethereum.beacon.core.types.BLSSignature; import org.ethereum.beacon.core.types.Bitfield; import tech.pegasys.artemis.util.bytes.Bytes96; @@ -22,15 +22,15 @@ public static List createRandomList(Random random, int maxCoun public static AttesterSlashing createRandom(Random random) { return new AttesterSlashing( - new SlashableAttestation( + new IndexedAttestation( + Collections.emptyList(), Collections.emptyList(), AttestationTestUtil.createRandomAttestationData(random), - Bitfield.EMPTY, BLSSignature.wrap(Bytes96.random(random))), - new SlashableAttestation( + new IndexedAttestation( + Collections.emptyList(), Collections.emptyList(), AttestationTestUtil.createRandomAttestationData(random), - Bitfield.EMPTY, BLSSignature.wrap(Bytes96.random(random))) ); } diff --git a/core/src/test/java/org/ethereum/beacon/core/util/DepositTestUtil.java b/core/src/test/java/org/ethereum/beacon/core/util/DepositTestUtil.java index ccf3ed057..1a5578abd 100644 --- a/core/src/test/java/org/ethereum/beacon/core/util/DepositTestUtil.java +++ b/core/src/test/java/org/ethereum/beacon/core/util/DepositTestUtil.java @@ -6,14 +6,14 @@ import java.util.Random; import org.ethereum.beacon.core.operations.Deposit; import org.ethereum.beacon.core.operations.deposit.DepositData; -import org.ethereum.beacon.core.operations.deposit.DepositInput; import org.ethereum.beacon.core.spec.SpecConstants; import org.ethereum.beacon.core.types.BLSPubkey; import org.ethereum.beacon.core.types.BLSSignature; -import org.ethereum.beacon.core.types.Time; import tech.pegasys.artemis.ethereum.core.Hash32; import tech.pegasys.artemis.util.bytes.Bytes48; import tech.pegasys.artemis.util.bytes.Bytes96; +import tech.pegasys.artemis.util.collections.ReadList; +import tech.pegasys.artemis.util.collections.ReadVector; import tech.pegasys.artemis.util.uint.UInt64; public abstract class DepositTestUtil { @@ -30,18 +30,14 @@ public static List createRandomList( } public static Deposit createRandom(Random random, SpecConstants spec, UInt64 depositIndex) { - DepositInput depositInput = - new DepositInput( - BLSPubkey.wrap(Bytes48.random(random)), - Hash32.random(random), - BLSSignature.wrap(Bytes96.random(random))); - DepositData depositData = new DepositData( - spec.getMaxDepositAmount(), Time.of(System.currentTimeMillis() / 1000), depositInput); + BLSPubkey.wrap(Bytes48.random(random)), + Hash32.random(random), + spec.getMaxEffectiveBalance(), BLSSignature.wrap(Bytes96.random(random))); - List merkleBranch = - Collections.nCopies(spec.getDepositContractTreeDepth().getIntValue(), Hash32.ZERO); + ReadVector merkleBranch = + ReadVector.wrap(Collections.nCopies(spec.getDepositContractTreeDepth().getIntValue(), Hash32.ZERO), Integer::new); return new Deposit(merkleBranch, depositIndex, depositData); } diff --git a/core/src/test/java/org/ethereum/beacon/core/util/Eth1DataTestUtil.java b/core/src/test/java/org/ethereum/beacon/core/util/Eth1DataTestUtil.java index 990e82ae5..5c82c1e38 100644 --- a/core/src/test/java/org/ethereum/beacon/core/util/Eth1DataTestUtil.java +++ b/core/src/test/java/org/ethereum/beacon/core/util/Eth1DataTestUtil.java @@ -3,11 +3,12 @@ import java.util.Random; import org.ethereum.beacon.core.state.Eth1Data; import tech.pegasys.artemis.ethereum.core.Hash32; +import tech.pegasys.artemis.util.uint.UInt64; public abstract class Eth1DataTestUtil { private Eth1DataTestUtil() {} public static Eth1Data createRandom(Random random) { - return new Eth1Data(Hash32.random(random), Hash32.random(random)); + return new Eth1Data(Hash32.random(random), UInt64.ZERO, Hash32.random(random)); } } diff --git a/crypto/src/main/java/org/ethereum/beacon/crypto/Hashes.java b/crypto/src/main/java/org/ethereum/beacon/crypto/Hashes.java index ed44f7cde..d90f8364e 100644 --- a/crypto/src/main/java/org/ethereum/beacon/crypto/Hashes.java +++ b/crypto/src/main/java/org/ethereum/beacon/crypto/Hashes.java @@ -2,7 +2,8 @@ import java.security.MessageDigest; import java.security.Security; -import org.bouncycastle.jcajce.provider.digest.Keccak; +import org.bouncycastle.jcajce.provider.digest.SHA256; +import org.bouncycastle.jcajce.provider.digest.SHA256.Digest; import org.bouncycastle.jce.provider.BouncyCastleProvider; import tech.pegasys.artemis.ethereum.core.Hash32; import tech.pegasys.artemis.util.bytes.Bytes32; @@ -14,7 +15,7 @@ private Hashes() {} private static final BouncyCastleProvider PROVIDER; - private static final String KECCAK256 = "KECCAK-256"; + private static final String SHA256 = "SHA-256"; static { Security.addProvider(PROVIDER = new BouncyCastleProvider()); @@ -32,7 +33,7 @@ private static byte[] digestUsingAlgorithm(BytesValue input, String algorithm) { try { // TODO integrate with JCA without performance loose // digest = MessageDigest.getInstance(algorithm, "BC"); - digest = new Keccak.Digest256(); + digest = new SHA256.Digest(); input.update(digest); return digest.digest(); } catch (Exception e) { @@ -41,13 +42,13 @@ private static byte[] digestUsingAlgorithm(BytesValue input, String algorithm) { } /** - * Calculates keccak256 hash. + * Calculates sha256 hash. * * @param input input message. * @return the hash. */ - public static Hash32 keccak256(BytesValue input) { - byte[] output = digestUsingAlgorithm(input, KECCAK256); + public static Hash32 sha256(BytesValue input) { + byte[] output = digestUsingAlgorithm(input, SHA256); return Hash32.wrap(Bytes32.wrap(output)); } } diff --git a/crypto/src/main/java/org/ethereum/beacon/crypto/bls/milagro/MilagroMessageMapper.java b/crypto/src/main/java/org/ethereum/beacon/crypto/bls/milagro/MilagroMessageMapper.java index bcf71310d..7710ba350 100644 --- a/crypto/src/main/java/org/ethereum/beacon/crypto/bls/milagro/MilagroMessageMapper.java +++ b/crypto/src/main/java/org/ethereum/beacon/crypto/bls/milagro/MilagroMessageMapper.java @@ -33,8 +33,8 @@ public ECP2 map(MessageParameters parameters) { BytesValue reBytes = parameters.getHash().concat(parameters.getDomain()).concat(BYTES_ONE); BytesValue imBytes = parameters.getHash().concat(parameters.getDomain()).concat(BYTES_TWO); - BIG reX = BIGs.fromBytes(Hashes.keccak256(reBytes)); - BIG imX = BIGs.fromBytes(Hashes.keccak256(imBytes)); + BIG reX = BIGs.fromBytes(Hashes.sha256(reBytes)); + BIG imX = BIGs.fromBytes(Hashes.sha256(imBytes)); FP2 x = new FP2(reX, imX); ECP2 point = createPoint(x); diff --git a/crypto/src/test/java/org/ethereum/beacon/crypto/BLS381Test.java b/crypto/src/test/java/org/ethereum/beacon/crypto/BLS381Test.java index a1300fc0b..608e3710e 100644 --- a/crypto/src/test/java/org/ethereum/beacon/crypto/BLS381Test.java +++ b/crypto/src/test/java/org/ethereum/beacon/crypto/BLS381Test.java @@ -26,7 +26,7 @@ public void checkSignAndVerifyFlow() { BytesValue message = randomMessage(); Bytes8 domain = randomDomain(); - MessageParameters params = new Impl(Hashes.keccak256(message), domain); + MessageParameters params = new Impl(Hashes.sha256(message), domain); Signature signature = BLS381.sign(params, keyPair); PublicKey decodedPublicKey = PublicKey.create(keyPair.getPublic().getEncodedBytes()); @@ -41,8 +41,8 @@ public void checkSignAndVerifyFlow() { public void failToVerifyIfMessageIsWrong() { KeyPair keyPair = BLS381.KeyPair.generate(); - MessageParameters rightMessage = new Impl(Hashes.keccak256(randomMessage()), randomDomain()); - MessageParameters wrongMessage = new Impl(Hashes.keccak256(randomMessage()), randomDomain()); + MessageParameters rightMessage = new Impl(Hashes.sha256(randomMessage()), randomDomain()); + MessageParameters wrongMessage = new Impl(Hashes.sha256(randomMessage()), randomDomain()); Signature signature = BLS381.sign(rightMessage, keyPair); boolean verified = BLS381.verify(wrongMessage, signature, keyPair.getPublic()); @@ -54,8 +54,8 @@ public void failToVerifyIfMessageIsWrong() { public void failToVerifyIfSignatureIsWrong() { KeyPair keyPair = BLS381.KeyPair.generate(); - MessageParameters rightMessage = new Impl(Hashes.keccak256(randomMessage()), randomDomain()); - MessageParameters wrongMessage = new Impl(Hashes.keccak256(randomMessage()), randomDomain()); + MessageParameters rightMessage = new Impl(Hashes.sha256(randomMessage()), randomDomain()); + MessageParameters wrongMessage = new Impl(Hashes.sha256(randomMessage()), randomDomain()); Signature wrongSignature = BLS381.sign(wrongMessage, keyPair); boolean verified = BLS381.verify(rightMessage, wrongSignature, keyPair.getPublic()); @@ -68,7 +68,7 @@ public void failToVerifyIfPubKeyIsWrong() { KeyPair rightKeyPair = BLS381.KeyPair.generate(); KeyPair wrongKeyPair = BLS381.KeyPair.generate(); - MessageParameters message = new Impl(Hashes.keccak256(randomMessage()), randomDomain()); + MessageParameters message = new Impl(Hashes.sha256(randomMessage()), randomDomain()); Signature signature = BLS381.sign(message, rightKeyPair); boolean verified = BLS381.verify(message, signature, wrongKeyPair.getPublic()); @@ -80,7 +80,7 @@ public void verifyAggregatedSignature() { KeyPair bob = BLS381.KeyPair.generate(); KeyPair alice = BLS381.KeyPair.generate(); - MessageParameters message = new Impl(Hashes.keccak256(randomMessage()), randomDomain()); + MessageParameters message = new Impl(Hashes.sha256(randomMessage()), randomDomain()); Signature bobSignature = BLS381.sign(message, bob); Signature aliceSignature = BLS381.sign(message, alice); @@ -99,8 +99,8 @@ public void failToVerifyIfWrongMessagesAggregated() { KeyPair bob = BLS381.KeyPair.generate(); KeyPair alice = BLS381.KeyPair.generate(); - MessageParameters message = new Impl(Hashes.keccak256(randomMessage()), randomDomain()); - MessageParameters wrongMessage = new Impl(Hashes.keccak256(randomMessage()), randomDomain()); + MessageParameters message = new Impl(Hashes.sha256(randomMessage()), randomDomain()); + MessageParameters wrongMessage = new Impl(Hashes.sha256(randomMessage()), randomDomain()); Signature bobSignature = BLS381.sign(message, bob); Signature wrongSignature = BLS381.sign(wrongMessage, alice); @@ -120,7 +120,7 @@ public void failToVerifyIfWrongSignaturesAggregated() { KeyPair alice = BLS381.KeyPair.generate(); KeyPair wrongKeyPair = BLS381.KeyPair.generate(); - MessageParameters message = new Impl(Hashes.keccak256(randomMessage()), randomDomain()); + MessageParameters message = new Impl(Hashes.sha256(randomMessage()), randomDomain()); Signature bobSignature = BLS381.sign(message, bob); Signature wrongSignature = BLS381.sign(message, wrongKeyPair); @@ -140,7 +140,7 @@ public void failToVerifyIfWrongPubKeysAggregated() { KeyPair alice = BLS381.KeyPair.generate(); KeyPair wrongKeyPair = BLS381.KeyPair.generate(); - MessageParameters message = new Impl(Hashes.keccak256(randomMessage()), randomDomain()); + MessageParameters message = new Impl(Hashes.sha256(randomMessage()), randomDomain()); Signature bobSignature = BLS381.sign(message, bob); Signature aliceSignature = BLS381.sign(message, alice); @@ -208,8 +208,8 @@ public void checkSignAndVerifyMultipleFlow() { BytesValue message2 = randomMessage(); Bytes8 domain = randomDomain(); - MessageParameters params1 = new MessageParameters.Impl(Hashes.keccak256(message1), domain); - MessageParameters params2 = new MessageParameters.Impl(Hashes.keccak256(message2), domain); + MessageParameters params1 = new MessageParameters.Impl(Hashes.sha256(message1), domain); + MessageParameters params2 = new MessageParameters.Impl(Hashes.sha256(message2), domain); Signature signature1 = BLS381.sign(params1, keyPair1); Signature signature2 = BLS381.sign(params2, keyPair2); @@ -235,8 +235,8 @@ public void failVerifyMultipleIfPublicKeysAreMixed() { BytesValue message2 = randomMessage(); Bytes8 domain = randomDomain(); - MessageParameters params1 = new MessageParameters.Impl(Hashes.keccak256(message1), domain); - MessageParameters params2 = new MessageParameters.Impl(Hashes.keccak256(message2), domain); + MessageParameters params1 = new MessageParameters.Impl(Hashes.sha256(message1), domain); + MessageParameters params2 = new MessageParameters.Impl(Hashes.sha256(message2), domain); Signature signature1 = BLS381.sign(params1, keyPair1); Signature signature2 = BLS381.sign(params2, keyPair2); @@ -261,8 +261,8 @@ public void checkVerifyMultipleIfPublicKeysAreSame() { BytesValue message2 = randomMessage(); Bytes8 domain = randomDomain(); - MessageParameters params1 = new MessageParameters.Impl(Hashes.keccak256(message1), domain); - MessageParameters params2 = new MessageParameters.Impl(Hashes.keccak256(message2), domain); + MessageParameters params1 = new MessageParameters.Impl(Hashes.sha256(message1), domain); + MessageParameters params2 = new MessageParameters.Impl(Hashes.sha256(message2), domain); Signature signature1 = BLS381.sign(params1, keyPair); Signature signature2 = BLS381.sign(params2, keyPair); @@ -285,7 +285,7 @@ public void throwIfMessagesAndPublicKeysDoNotMatch() { BytesValue message = randomMessage(); Bytes8 domain = randomDomain(); - MessageParameters params = new MessageParameters.Impl(Hashes.keccak256(message), domain); + MessageParameters params = new MessageParameters.Impl(Hashes.sha256(message), domain); Signature signature = BLS381.sign(params, keyPair); assertThatThrownBy( diff --git a/pow/core/src/main/java/org/ethereum/beacon/pow/AbstractDepositContract.java b/pow/core/src/main/java/org/ethereum/beacon/pow/AbstractDepositContract.java index 8cc93d7ba..b7fad35ae 100644 --- a/pow/core/src/main/java/org/ethereum/beacon/pow/AbstractDepositContract.java +++ b/pow/core/src/main/java/org/ethereum/beacon/pow/AbstractDepositContract.java @@ -4,11 +4,13 @@ import java.util.Arrays; import java.util.List; import java.util.Optional; +import java.util.function.Function; import java.util.stream.Collectors; import org.ethereum.beacon.core.operations.Deposit; import org.ethereum.beacon.core.operations.deposit.DepositData; -import org.ethereum.beacon.core.operations.deposit.DepositInput; import org.ethereum.beacon.core.state.Eth1Data; +import org.ethereum.beacon.core.types.BLSPubkey; +import org.ethereum.beacon.core.types.BLSSignature; import org.ethereum.beacon.core.types.Gwei; import org.ethereum.beacon.core.types.Time; import org.ethereum.beacon.schedulers.Schedulers; @@ -20,7 +22,10 @@ import reactor.core.publisher.MonoProcessor; import tech.pegasys.artemis.ethereum.core.Hash32; import tech.pegasys.artemis.util.bytes.Bytes32; +import tech.pegasys.artemis.util.bytes.Bytes48; import tech.pegasys.artemis.util.bytes.Bytes8; +import tech.pegasys.artemis.util.bytes.Bytes96; +import tech.pegasys.artemis.util.collections.ReadVector; import tech.pegasys.artemis.util.uint.UInt64; public abstract class AbstractDepositContract implements DepositContract { @@ -74,6 +79,7 @@ protected synchronized void chainStart(byte[] deposit_root, byte[] time, byte[] ChainStart chainStart = new ChainStart( Time.castFrom(UInt64.fromBytesBigEndian(Bytes8.wrap(time))), new Eth1Data(Hash32.wrap(Bytes32.wrap(deposit_root)), + UInt64.valueOf(initialDeposits.size()), Hash32.wrap(Bytes32.wrap(blockHash))), initialDeposits); chainStartSink.onNext(chainStart); @@ -106,20 +112,23 @@ private DepositInfo createDepositInfo(DepositEventData eventData, byte[] blockHa List merkleBranch = Arrays.stream(eventData.merkle_branch) .map(bytes -> Hash32.wrap(Bytes32.wrap(bytes))) .collect(Collectors.toList()); - Deposit deposit = new Deposit(merkleBranch, + Deposit deposit = new Deposit(ReadVector.wrap(merkleBranch, Function.identity()), UInt64.fromBytesBigEndian(Bytes8.wrap(eventData.merkle_tree_index)), parseDepositData(eventData.data)); return new DepositInfo(deposit, new Eth1Data(Hash32.wrap(Bytes32.wrap(eventData.deposit_root)), + UInt64.ZERO, Hash32.wrap(Bytes32.wrap(blockHash)))); } private DepositData parseDepositData(byte[] data) { - Gwei amount = Gwei.castFrom(UInt64.fromBytesBigEndian(Bytes8.wrap(data, 0))); - Time timestamp = Time.castFrom(UInt64.fromBytesBigEndian(Bytes8.wrap(data, 8))); - DepositInput depositInput = ssz.decode(Arrays.copyOfRange(data, 16, data.length), - DepositInput.class); - return new DepositData(amount, timestamp, depositInput); + BLSPubkey pubkey = BLSPubkey.wrap(Bytes48.wrap(data, 0)); + Hash32 withdrawalCredentials = Hash32.wrap(Bytes32.wrap(data, 48)); + Gwei amount = + Gwei.castFrom(UInt64.fromBytesLittleEndian(Bytes8.wrap(data, Bytes48.SIZE + Bytes32.SIZE))); + BLSSignature signature = + BLSSignature.wrap(Bytes96.wrap(data, Bytes48.SIZE + Bytes32.SIZE + Bytes8.SIZE)); + return new DepositData(pubkey, withdrawalCredentials, amount, signature); } @Override @@ -134,6 +143,7 @@ public Optional getLatestEth1Data() { return getLatestBlockHashDepositRoot().map( r -> new Eth1Data( Hash32.wrap(Bytes32.wrap(r.getValue1())), + UInt64.ZERO, Hash32.wrap(Bytes32.wrap(r.getValue0())))); } diff --git a/pow/ethereumj/src/main/java/org/ethereum/beacon/pow/EthereumJTransactionBuilder.java b/pow/ethereumj/src/main/java/org/ethereum/beacon/pow/EthereumJTransactionBuilder.java index 19feafeb3..103a0b24e 100644 --- a/pow/ethereumj/src/main/java/org/ethereum/beacon/pow/EthereumJTransactionBuilder.java +++ b/pow/ethereumj/src/main/java/org/ethereum/beacon/pow/EthereumJTransactionBuilder.java @@ -1,5 +1,6 @@ package org.ethereum.beacon.pow; +import org.ethereum.beacon.core.operations.deposit.DepositData; import org.ethereum.beacon.core.types.Gwei; import org.ethereum.beacon.pow.validator.TransactionBuilder; import org.ethereum.core.CallTransaction; @@ -37,7 +38,7 @@ private boolean isReady() { @Override public CompletableFuture createTransaction( - String fromAddress, BytesValue depositInput, Gwei amount) { + String fromAddress, DepositData depositData, Gwei amount) { CompletableFuture result = new CompletableFuture<>(); executeOnSyncDone( () -> { @@ -46,7 +47,10 @@ public CompletableFuture createTransaction( .getRepository() .getNonce(Address.fromHexString(fromAddress).getArrayUnsafe()); byte[] data = - contract.getByName("deposit").encode((Object) depositInput.getArrayUnsafe()); + contract.getByName("deposit").encode( + depositData.getPubKey().getArrayUnsafe(), + depositData.getWithdrawalCredentials().getArrayUnsafe(), + depositData.getSignature().getArrayUnsafe()); Transaction tx = ethereum.createTransaction( nonce, diff --git a/pow/ethereumj/src/test/java/org/ethereum/beacon/pow/StandaloneDepositContractTest.java b/pow/ethereumj/src/test/java/org/ethereum/beacon/pow/StandaloneDepositContractTest.java index ca2923c07..2c80b91dd 100644 --- a/pow/ethereumj/src/test/java/org/ethereum/beacon/pow/StandaloneDepositContractTest.java +++ b/pow/ethereumj/src/test/java/org/ethereum/beacon/pow/StandaloneDepositContractTest.java @@ -7,10 +7,7 @@ import java.util.List; import java.util.Optional; import org.apache.commons.codec.binary.Hex; -import org.ethereum.beacon.core.operations.deposit.DepositInput; import org.ethereum.beacon.core.state.Eth1Data; -import org.ethereum.beacon.core.types.BLSPubkey; -import org.ethereum.beacon.core.types.BLSSignature; import org.ethereum.beacon.pow.DepositContract.ChainStart; import org.ethereum.beacon.pow.DepositContract.DepositInfo; import org.ethereum.beacon.schedulers.Schedulers; @@ -24,6 +21,7 @@ import org.ethereum.util.blockchain.StandaloneBlockchain; import org.ethereum.util.blockchain.StandaloneBlockchain.SolidityContractImpl; import org.junit.Assert; +import org.junit.Ignore; import org.junit.Test; import reactor.core.publisher.Mono; import tech.pegasys.artemis.ethereum.core.Hash32; @@ -33,6 +31,7 @@ import tech.pegasys.artemis.util.bytes.MutableBytes48; import tech.pegasys.artemis.util.uint.UInt64; +@Ignore public class StandaloneDepositContractTest { // modified contract: @@ -64,13 +63,13 @@ public void test1() { for(int i = 0; i < 20; i++) { MutableBytes48 pubKey = MutableBytes48.create(); pubKey.set(0, (byte) i); - DepositInput depositInput = new DepositInput(BLSPubkey.wrap(pubKey), Hash32.ZERO, BLSSignature.wrap(Bytes96.ZERO)); - BytesValue depositInputBytes = sszSerializer.encode2(depositInput); SolidityCallResult result = contract.callFunction( depositAmount, "deposit", - (Object) depositInputBytes.extractArray()); + pubKey.extractArray(), + Hash32.ZERO.extractArray(), + Bytes96.ZERO.extractArray()); Assert.assertTrue(result.isSuccessful()); Assert.assertEquals(i == 15 ? 2 : 1, result.getEvents().size()); @@ -97,8 +96,8 @@ public void test1() { .getBlockByHash(chainStart.getEth1Data().getBlockHash().extractArray()).getNumber()); for (int i = 0; i < 16; i++) { Assert.assertEquals(UInt64.valueOf(i), chainStart.getInitialDeposits().get(i).getIndex()); - Assert.assertEquals((byte) i, chainStart.getInitialDeposits().get(i).getDepositData() - .getDepositInput().getPubKey().get(0)); + Assert.assertEquals((byte) i, chainStart.getInitialDeposits().get(i).getData() + .getPubKey().get(0)); } depositRoot = contract.callConstFunction("get_deposit_root"); @@ -106,6 +105,7 @@ public void test1() { Eth1Data lastDepositEthData = new Eth1Data( Hash32.wrap(Bytes32.wrap((byte[]) depositRoot[0])), + UInt64.ZERO, Hash32.wrap(Bytes32.wrap(sb.getBlockchain().getBlockByNumber(21).getHash()))); List depositInfos1 = depositContract.peekDeposits(2, @@ -113,18 +113,18 @@ public void test1() { Assert.assertEquals(2, depositInfos1.size()); Assert.assertEquals((byte) 16, - depositInfos1.get(0).getDeposit().getDepositData().getDepositInput().getPubKey().get(0)); + depositInfos1.get(0).getDeposit().getData().getPubKey().get(0)); Assert.assertEquals((byte) 17, - depositInfos1.get(1).getDeposit().getDepositData().getDepositInput().getPubKey().get(0)); + depositInfos1.get(1).getDeposit().getData().getPubKey().get(0)); List depositInfos2 = depositContract.peekDeposits(200, depositInfos1.get(1).getEth1Data(), lastDepositEthData); Assert.assertEquals(2, depositInfos2.size()); Assert.assertEquals((byte) 18, - depositInfos2.get(0).getDeposit().getDepositData().getDepositInput().getPubKey().get(0)); + depositInfos2.get(0).getDeposit().getData().getPubKey().get(0)); Assert.assertEquals((byte) 19, - depositInfos2.get(1).getDeposit().getDepositData().getDepositInput().getPubKey().get(0)); + depositInfos2.get(1).getDeposit().getData().getPubKey().get(0)); List depositInfos3 = depositContract.peekDeposits(200, lastDepositEthData, lastDepositEthData); @@ -160,13 +160,13 @@ public void testOnline() { for(int i = 0; i < 16; i++) { MutableBytes48 pubKey = MutableBytes48.create(); pubKey.set(0, (byte) i); - DepositInput depositInput = new DepositInput(BLSPubkey.wrap(pubKey), Hash32.ZERO, BLSSignature.wrap(Bytes96.ZERO)); - BytesValue depositInputBytes = sszSerializer.encode2(depositInput); SolidityCallResult result = contract.callFunction( depositAmount, "deposit", - (Object) depositInputBytes.extractArray()); + pubKey.extractArray(), + Hash32.ZERO.extractArray(), + Bytes96.ZERO.extractArray()); sb.createBlock(); sb.createBlock(); @@ -187,8 +187,8 @@ public void testOnline() { .getBlockByHash(chainStart.getEth1Data().getBlockHash().extractArray()).getNumber()); for (int i = 0; i < 16; i++) { Assert.assertEquals(UInt64.valueOf(i), chainStart.getInitialDeposits().get(i).getIndex()); - Assert.assertEquals((byte) i, chainStart.getInitialDeposits().get(i).getDepositData() - .getDepositInput().getPubKey().get(0)); + Assert.assertEquals((byte) i, chainStart.getInitialDeposits().get(i).getData() + .getPubKey().get(0)); } Optional latestEth1Data1 = depositContract.getLatestEth1Data(); @@ -199,11 +199,9 @@ public void testOnline() { for (int j = 0; j < 4; j++) { MutableBytes48 pubKey = MutableBytes48.create(); pubKey.set(0, (byte) (0x20 + i * 4 + j)); - DepositInput depositInput = new DepositInput(BLSPubkey.wrap(pubKey), Hash32.ZERO, BLSSignature.wrap(Bytes96.ZERO)); - BytesValue depositInputBytes = sszSerializer.encode2(depositInput); contract.callFunction(depositAmount,"deposit", - (Object) depositInputBytes.extractArray()); + pubKey.extractArray(), Hash32.ZERO.extractArray(), Bytes96.ZERO.extractArray()); } sb.createBlock(); sb.createBlock(); @@ -233,8 +231,8 @@ public void testOnline() { } Assert.assertEquals(16, allDepos.size()); for (int i = 0; i < 16; i++) { - Assert.assertEquals(0x20 + i, allDepos.get(i).getDeposit().getDepositData() - .getDepositInput().getPubKey().get(0)); + Assert.assertEquals(0x20 + i, allDepos.get(i).getDeposit().getData() + .getPubKey().get(0)); } } diff --git a/pow/validator/src/main/java/org/ethereum/beacon/pow/validator/TransactionBuilder.java b/pow/validator/src/main/java/org/ethereum/beacon/pow/validator/TransactionBuilder.java index 2bc2efae2..8e9d58fcf 100644 --- a/pow/validator/src/main/java/org/ethereum/beacon/pow/validator/TransactionBuilder.java +++ b/pow/validator/src/main/java/org/ethereum/beacon/pow/validator/TransactionBuilder.java @@ -1,5 +1,6 @@ package org.ethereum.beacon.pow.validator; +import org.ethereum.beacon.core.operations.deposit.DepositData; import org.ethereum.beacon.core.types.Gwei; import tech.pegasys.artemis.util.bytes.BytesValue; @@ -7,7 +8,7 @@ /** Util for creating validator transactions */ public interface TransactionBuilder { - CompletableFuture createTransaction(String fromAddress, BytesValue depositInput, Gwei amount); + CompletableFuture createTransaction(String fromAddress, DepositData depositData, Gwei amount); CompletableFuture signTransaction(BytesValue unsignedTransaction, BytesValue eth1PrivKey); } diff --git a/pow/validator/src/main/java/org/ethereum/beacon/pow/validator/ValidatorRegistrationServiceImpl.java b/pow/validator/src/main/java/org/ethereum/beacon/pow/validator/ValidatorRegistrationServiceImpl.java index 83a48afd2..7bd2c4425 100644 --- a/pow/validator/src/main/java/org/ethereum/beacon/pow/validator/ValidatorRegistrationServiceImpl.java +++ b/pow/validator/src/main/java/org/ethereum/beacon/pow/validator/ValidatorRegistrationServiceImpl.java @@ -7,7 +7,7 @@ import org.ethereum.beacon.consensus.transition.PerBlockTransition; import org.ethereum.beacon.core.BeaconState; import org.ethereum.beacon.core.operations.Deposit; -import org.ethereum.beacon.core.operations.deposit.DepositInput; +import org.ethereum.beacon.core.operations.deposit.DepositData; import org.ethereum.beacon.core.state.ValidatorRecord; import org.ethereum.beacon.core.types.BLSSignature; import org.ethereum.beacon.core.types.EpochNumber; @@ -254,36 +254,31 @@ private void sendDepositAndWait() { private Optional onDeposit(Deposit deposit) { return Optional.of(deposit) - .filter(d -> d.getDepositData().getDepositInput().getPubKey().equals(blsCredentials.getPubkey())); + .filter(d -> d.getData().getPubKey().equals(blsCredentials.getPubkey())); } private CompletableFuture submitDeposit( Gwei amount, Address eth1From, BytesValue eth1PrivKey) { - DepositInput depositInput = createDepositInput(); - return createTransaction(eth1From, eth1PrivKey, depositInput, amount) + DepositData depositData = createDepositData(amount); + return createTransaction(eth1From, eth1PrivKey, depositData, amount) .thenCompose(transactionGateway::send); } - private DepositInput createDepositInput() { + private DepositData createDepositData(Gwei amount) { // To submit a deposit: // - // Pack the validator's initialization parameters into deposit_input, a DepositInput SSZ - // object. - // Set deposit_input.proof_of_possession = EMPTY_SIGNATURE. - DepositInput preDepositInput = - new DepositInput(blsCredentials.getPubkey(), withdrawalCredentials, BLSSignature.ZERO); - // Let proof_of_possession be the result of bls_sign of the hash_tree_root(deposit_input) with + // Instantiate a deposit_data object. + // Set deposit_data.signature = BLSSignature.ZERO. + DepositData preDepositData = new DepositData(blsCredentials.getPubkey(), withdrawalCredentials, + amount, BLSSignature.ZERO); + // Let signature be the result of bls_sign of the signing_hash(deposit_data) with // domain=DOMAIN_DEPOSIT. - Hash32 hash = spec.signed_root(preDepositInput); + Hash32 hash = spec.signing_root(preDepositData); BeaconState latestState = getLatestState(); - UInt64 domain = - spec.get_domain( - latestState.getFork(), spec.get_current_epoch(latestState), DEPOSIT); + UInt64 domain = spec.get_domain(latestState, DEPOSIT); BLSSignature signature = blsCredentials.getSigner().sign(hash, domain); - // Set deposit_input.proof_of_possession = proof_of_possession. - DepositInput depositInput = new DepositInput(blsCredentials.getPubkey(), withdrawalCredentials, signature); - - return depositInput; + // Set deposit_data.signature = signature. + return new DepositData(blsCredentials.getPubkey(), withdrawalCredentials, amount, signature); } @Override @@ -292,26 +287,25 @@ public Optional getValidatorService() { } private CompletableFuture createTransaction( - Address eth1From, BytesValue eth1PrivKey, DepositInput depositInput, Gwei amount) { + Address eth1From, BytesValue eth1PrivKey, DepositData depositData, Gwei amount) { // Let amount be the amount in Gwei to be deposited by the validator where MIN_DEPOSIT_AMOUNT <= - // amount <= MAX_DEPOSIT_AMOUNT. + // amount <= MAX_EFFECTIVE_BALANCE. if (amount.compareTo(spec.getConstants().getMinDepositAmount()) < 0) { throw new RuntimeException( String.format( "Deposit amount should be equal or greater than %s (defined by spec)", spec.getConstants().getMinDepositAmount())); } - if (amount.compareTo(spec.getConstants().getMaxDepositAmount()) > 0) { + if (amount.compareTo(spec.getConstants().getMaxEffectiveBalance()) > 0) { throw new RuntimeException( String.format( "Deposit amount should be equal or less than %s (defined by spec)", - spec.getConstants().getMaxDepositAmount())); + spec.getConstants().getMaxEffectiveBalance())); } // Send a transaction on the Ethereum 1.0 chain to DEPOSIT_CONTRACT_ADDRESS executing deposit - // along with serialize(deposit_input) as the singular bytes input along with a deposit amount - // in Gwei. + // along with deposit_data and a deposit amount in Gwei. return transactionBuilder - .createTransaction(eth1From.toString(), sszSerializer.encode2(depositInput), amount) + .createTransaction(eth1From.toString(), depositData, amount) .thenCompose(unsignedTx -> transactionBuilder.signTransaction(unsignedTx, eth1PrivKey)); } } diff --git a/ssz/src/main/java/org/ethereum/beacon/ssz/access/basic/BytesCodec.java b/ssz/src/main/java/org/ethereum/beacon/ssz/access/basic/BytesCodec.java index 62a12b320..4c4115efb 100644 --- a/ssz/src/main/java/org/ethereum/beacon/ssz/access/basic/BytesCodec.java +++ b/ssz/src/main/java/org/ethereum/beacon/ssz/access/basic/BytesCodec.java @@ -9,6 +9,7 @@ import org.ethereum.beacon.ssz.access.SSZBasicAccessor; import tech.pegasys.artemis.ethereum.core.Address; import tech.pegasys.artemis.util.bytes.Bytes1; +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; @@ -36,6 +37,7 @@ public class BytesCodec implements SSZBasicAccessor { static { supportedClassTypes.add(Bytes1.class); supportedClassTypes.add(Bytes4.class); + supportedClassTypes.add(Bytes32.class); supportedClassTypes.add(Bytes48.class); supportedClassTypes.add(Bytes96.class); supportedClassTypes.add(Address.class); @@ -44,6 +46,7 @@ public class BytesCodec implements SSZBasicAccessor { static { classToByteType.put(Bytes1.class, BytesType.of(1)); classToByteType.put(Bytes4.class, BytesType.of(4)); + classToByteType.put(Bytes32.class, BytesType.of(32)); classToByteType.put(Bytes48.class, BytesType.of(48)); classToByteType.put(Bytes96.class, BytesType.of(96)); classToByteType.put(Address.class, BytesType.of(20)); @@ -137,10 +140,14 @@ public Object decode(SSZField field, BytesSSZReaderProxy reader) { { return Address.wrap(BytesValue.of(reader.readHash(bytesType.size).toArrayUnsafe())); } + case 32: + { + return Bytes32.wrap(reader.readHash(bytesType.size).toArrayUnsafe()); + } case 48: - { - return Bytes48.wrap(reader.readHash(bytesType.size).toArrayUnsafe()); - } + { + return Bytes48.wrap(reader.readHash(bytesType.size).toArrayUnsafe()); + } case 96: { return Bytes96.wrap(reader.readHash(bytesType.size).toArrayUnsafe()); @@ -198,15 +205,24 @@ public List decodeList( .collect(Collectors.toList()); break; } + case 32: + { + res = + bytesList.stream() + .map(Bytes::toArrayUnsafe) + .map(Bytes32::wrap) + .collect(Collectors.toList()); + break; + } case 48: - { - res = - bytesList.stream() - .map(Bytes::toArrayUnsafe) - .map(Bytes48::wrap) - .collect(Collectors.toList()); - break; - } + { + res = + bytesList.stream() + .map(Bytes::toArrayUnsafe) + .map(Bytes48::wrap) + .collect(Collectors.toList()); + break; + } case 96: { res = diff --git a/ssz/src/test/java/org/ethereum/beacon/ssz/SSZIncrementalTest.java b/ssz/src/test/java/org/ethereum/beacon/ssz/SSZIncrementalTest.java index 2c51c81c9..6e9bcc0f6 100644 --- a/ssz/src/test/java/org/ethereum/beacon/ssz/SSZIncrementalTest.java +++ b/ssz/src/test/java/org/ethereum/beacon/ssz/SSZIncrementalTest.java @@ -37,7 +37,7 @@ private static class CountingHash implements Function { @Override public Hash32 apply(BytesValue bytesValue) { counter++; - return Hashes.keccak256(bytesValue); + return Hashes.sha256(bytesValue); } } diff --git a/ssz/src/test/java/org/ethereum/beacon/ssz/SSZSerializerTest.java b/ssz/src/test/java/org/ethereum/beacon/ssz/SSZSerializerTest.java index 75994b3e6..bc6cde12b 100644 --- a/ssz/src/test/java/org/ethereum/beacon/ssz/SSZSerializerTest.java +++ b/ssz/src/test/java/org/ethereum/beacon/ssz/SSZSerializerTest.java @@ -1,8 +1,6 @@ package org.ethereum.beacon.ssz; import java.util.Arrays; -import net.consensys.cava.bytes.Bytes; -import net.consensys.cava.ssz.SSZ; import org.ethereum.beacon.crypto.Hashes; import org.ethereum.beacon.ssz.access.container.SSZAnnotationSchemeBuilder; import org.ethereum.beacon.ssz.annotation.SSZSerializable; @@ -32,7 +30,7 @@ /** Tests of {@link SSZSerializer} */ public class SSZSerializerTest { private static byte[] DEFAULT_HASH = - Hashes.keccak256(BytesValue.fromHexString("aa")).getArrayUnsafe(); + Hashes.sha256(BytesValue.fromHexString("aa")).getArrayUnsafe(); private static Sign.Signature DEFAULT_SIG = new Sign.Signature(); static { diff --git a/ssz/src/test/java/org/ethereum/beacon/ssz/SSZTypeTest.java b/ssz/src/test/java/org/ethereum/beacon/ssz/SSZTypeTest.java index 34487a879..8f4a00019 100644 --- a/ssz/src/test/java/org/ethereum/beacon/ssz/SSZTypeTest.java +++ b/ssz/src/test/java/org/ethereum/beacon/ssz/SSZTypeTest.java @@ -339,7 +339,7 @@ public static class H2 { @Test public void testHashTruncated1() throws Exception { - SSZHasher hasher = new SSZBuilder().buildHasher(Hashes::keccak256); + SSZHasher hasher = new SSZBuilder().buildHasher(Hashes::sha256); H1 h1 = new H1(); h1.a1 = 0x1111; diff --git a/start/benchmaker/src/main/java/org/ethereum/beacon/benchmaker/Benchmaker.java b/start/benchmaker/src/main/java/org/ethereum/beacon/benchmaker/Benchmaker.java index 96606fa91..1f04ee35e 100644 --- a/start/benchmaker/src/main/java/org/ethereum/beacon/benchmaker/Benchmaker.java +++ b/start/benchmaker/src/main/java/org/ethereum/beacon/benchmaker/Benchmaker.java @@ -85,7 +85,7 @@ public void run() { new Builder() .withConstants(constants) .withDefaultHashFunction() - .withHasher(SSZObjectHasher.create(constants, Hashes::keccak256, !noIncrement)) + .withHasher(SSZObjectHasher.create(constants, Hashes::sha256, !noIncrement)) .withBlsVerify(!noBls) .withCache(!noCache) .withBlsVerifyProofOfPossession(false); diff --git a/start/benchmaker/src/main/java/org/ethereum/beacon/benchmaker/BenchmarkRunner.java b/start/benchmaker/src/main/java/org/ethereum/beacon/benchmaker/BenchmarkRunner.java index 8adc1b730..dd403a1db 100644 --- a/start/benchmaker/src/main/java/org/ethereum/beacon/benchmaker/BenchmarkRunner.java +++ b/start/benchmaker/src/main/java/org/ethereum/beacon/benchmaker/BenchmarkRunner.java @@ -45,6 +45,7 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import tech.pegasys.artemis.ethereum.core.Hash32; +import tech.pegasys.artemis.util.uint.UInt64; public class BenchmarkRunner implements Runnable { private static final Logger logger = LogManager.getLogger("benchmaker"); @@ -71,7 +72,7 @@ private Pair, List> getValidatorDeposits(BeaconChainSpec for (int i = 0; i < count; i++) { BLS381.KeyPair keyPair = keyPairReader.next(); keyPairs.add(keyPair); - deposits.add(SimulateUtils.getDepositForKeyPair(rnd, keyPair, spec, false)); + deposits.add(SimulateUtils.getDepositForKeyPair(UInt64.valueOf(i), rnd, keyPair, spec, false)); } return Pair.with(deposits, keyPairs); @@ -97,7 +98,7 @@ public void run() { MDCControlledSchedulers controlledSchedulers = new MDCControlledSchedulers(); controlledSchedulers.setCurrentTime(genesisTime.getMillis().getValue() + 1000); - Eth1Data eth1Data = new Eth1Data(Hash32.ZERO, Hash32.ZERO); + Eth1Data eth1Data = new Eth1Data(Hash32.ZERO, UInt64.ZERO, Hash32.ZERO); LocalWireHub localWireHub = new LocalWireHub(s -> {}, controlledSchedulers.createNew("wire")); diff --git a/start/common/src/main/java/org/ethereum/beacon/bench/BenchmarkReport.java b/start/common/src/main/java/org/ethereum/beacon/bench/BenchmarkReport.java index 85f35d3cf..e3420413a 100644 --- a/start/common/src/main/java/org/ethereum/beacon/bench/BenchmarkReport.java +++ b/start/common/src/main/java/org/ethereum/beacon/bench/BenchmarkReport.java @@ -348,15 +348,12 @@ private String[] getFunctionList(BenchmarkRoutine routine, MeasurementGroup grou TOP_METHOD_LIST.put( BenchmarkRoutine.EPOCH, new String[] { - "update_justification_and_finalization", + "process_justification_and_finalization", "process_crosslinks", - "maybe_reset_eth1_period", - "apply_rewards", - "process_ejections", - "update_registry_and_shuffling_data", + "process_rewards_and_penalties", + "process_registry_updates", "process_slashings", - "process_exit_queue", - "finish_epoch_update" + "process_final_updates" }); } @@ -366,15 +363,15 @@ private String[] getFunctionList(BenchmarkRoutine routine, MeasurementGroup grou private static final String[] HELPER_FUNCTIONS = { "hash_tree_root", - "signed_root", - "get_crosslink_committees_at_slot", + "signing_root", + "get_crosslink_committee", "get_beacon_proposer_index", "get_active_validator_indices", "get_total_balance", - "get_attestation_participants", + "get_attesting_indices", "get_validator_index_by_pubkey", "get_previous_total_balance", - "get_current_total_balance", + "get_total_active_balance", "get_base_reward", "verify_bitfield" }; diff --git a/start/common/src/main/java/org/ethereum/beacon/bench/BenchmarkingBeaconChainSpec.java b/start/common/src/main/java/org/ethereum/beacon/bench/BenchmarkingBeaconChainSpec.java index e35f57cee..311b8c5da 100644 --- a/start/common/src/main/java/org/ethereum/beacon/bench/BenchmarkingBeaconChainSpec.java +++ b/start/common/src/main/java/org/ethereum/beacon/bench/BenchmarkingBeaconChainSpec.java @@ -17,12 +17,12 @@ import org.ethereum.beacon.core.operations.attestation.AttestationData; import org.ethereum.beacon.core.spec.SpecConstants; import org.ethereum.beacon.core.state.ShardCommittee; -import org.ethereum.beacon.core.state.ValidatorRecord; import org.ethereum.beacon.core.types.BLSPubkey; import org.ethereum.beacon.core.types.BLSSignature; import org.ethereum.beacon.core.types.Bitfield; import org.ethereum.beacon.core.types.EpochNumber; import org.ethereum.beacon.core.types.Gwei; +import org.ethereum.beacon.core.types.ShardNumber; import org.ethereum.beacon.core.types.SlotNumber; import org.ethereum.beacon.core.types.ValidatorIndex; import org.ethereum.beacon.crypto.BLS381.PublicKey; @@ -30,7 +30,6 @@ import org.ethereum.beacon.util.stats.TimeCollector; import tech.pegasys.artemis.ethereum.core.Hash32; import tech.pegasys.artemis.util.bytes.BytesValue; -import tech.pegasys.artemis.util.collections.ReadList; import tech.pegasys.artemis.util.uint.UInt64; public class BenchmarkingBeaconChainSpec extends CachingBeaconChainSpec { @@ -74,6 +73,9 @@ public Function getHashFunction() { return super.getHashFunction(); } + + /** BLS */ + @Override public boolean bls_verify( BLSPubkey publicKey, Hash32 message, BLSSignature signature, UInt64 domain) { @@ -95,170 +97,160 @@ public PublicKey bls_aggregate_pubkeys(List publicKeysBytes) { "bls_aggregate_pubkeys", () -> super.bls_aggregate_pubkeys(publicKeysBytes)); } + + /** HELPERS */ + @Override public Hash32 hash_tree_root(Object object) { return callAndTrack("hash_tree_root", () -> super.hash_tree_root(object)); } @Override - public Hash32 signed_root(Object object) { - return callAndTrack("signed_root", () -> super.signed_root(object)); + public Hash32 signing_root(Object object) { + return callAndTrack("signing_root", () -> super.signing_root(object)); } @Override - public List get_crosslink_committees_at_slot(BeaconState state, SlotNumber slot) { + public List get_crosslink_committee(BeaconState state, EpochNumber epoch, + ShardNumber shard) { return callAndTrack( - "get_crosslink_committees_at_slot", - () -> super.get_crosslink_committees_at_slot(state, slot)); + "get_crosslink_committee", + () -> super.get_crosslink_committee(state, epoch, shard)); } @Override - public ValidatorIndex get_beacon_proposer_index(BeaconState state, SlotNumber slot) { + public ValidatorIndex get_beacon_proposer_index(BeaconState state) { return callAndTrack( - "get_beacon_proposer_index", () -> super.get_beacon_proposer_index(state, slot)); + "get_beacon_proposer_index", () -> super.get_beacon_proposer_index(state)); } @Override - public void update_justification_and_finalization(MutableBeaconState state) { - callAndTrack( - "update_justification_and_finalization", - () -> super.update_justification_and_finalization(state)); + public List get_active_validator_indices( + BeaconState state, EpochNumber epochNumber) { + return callAndTrack( + "get_active_validator_indices", + () -> super.get_active_validator_indices(state, epochNumber)); } @Override - public void process_crosslinks(MutableBeaconState state) { - callAndTrack("process_crosslinks", () -> super.process_crosslinks(state)); + public Gwei get_total_balance(BeaconState state, Collection validators) { + return callAndTrack("get_total_balance", () -> super.get_total_balance(state, validators)); } @Override - public void maybe_reset_eth1_period(MutableBeaconState state) { - callAndTrack("maybe_reset_eth1_period", () -> super.maybe_reset_eth1_period(state)); + public List get_attesting_indices( + BeaconState state, AttestationData attestation_data, Bitfield bitfield) { + return callAndTrack( + "get_attesting_indices", + () -> super.get_attesting_indices(state, attestation_data, bitfield)); } @Override - public void apply_rewards(MutableBeaconState state) { - callAndTrack("apply_rewards", () -> super.apply_rewards(state)); + public ValidatorIndex get_validator_index_by_pubkey(BeaconState state, BLSPubkey pubkey) { + return callAndTrack( + "get_validator_index_by_pubkey", () -> super.get_validator_index_by_pubkey(state, pubkey)); } @Override - public List process_ejections(MutableBeaconState state) { - return callAndTrack("process_ejections", () -> super.process_ejections(state)); + public Gwei get_base_reward(BeaconState state, ValidatorIndex index) { + return callAndTrack("get_base_reward", () -> super.get_base_reward(state, index)); } @Override - public void update_registry_and_shuffling_data(MutableBeaconState state) { - callAndTrack( - "update_registry_and_shuffling_data", - () -> super.update_registry_and_shuffling_data(state)); + public Gwei get_total_active_balance(BeaconState state) { + return callAndTrack("get_total_active_balance", () -> super.get_total_active_balance(state)); } @Override - public void process_slashings(MutableBeaconState state) { - callAndTrack("process_slashings", () -> super.process_slashings(state)); + public boolean verify_bitfield(Bitfield bitfield, int committee_size) { + return callAndTrack("verify_bitfield", () -> super.verify_bitfield(bitfield, committee_size)); } - @Override - public void process_exit_queue(MutableBeaconState state) { - callAndTrack("process_exit_queue", () -> super.process_exit_queue(state)); - } - @Override - public void finish_epoch_update(MutableBeaconState state) { - callAndTrack("finish_epoch_update", () -> super.finish_epoch_update(state)); - } + /** STATE CACHING */ @Override public void cache_state(MutableBeaconState state) { callAndTrack("cache_state", () -> super.cache_state(state)); } + /** SLOT PROCESSING */ + @Override public void advance_slot(MutableBeaconState state) { callAndTrack("advance_slot", () -> super.advance_slot(state)); } - @Override - public void process_attestation(MutableBeaconState state, Attestation attestation) { - callAndTrack( - "process_attestation", - () -> { - // count verification in benchmark measurements - super.verify_attestation(state, attestation); - super.process_attestation(state, attestation); - }); - } - @Override - public void process_block_header(MutableBeaconState state, BeaconBlock block) { - callAndTrack( - "process_block_header", - () -> { - super.verify_block_header(state, block); - super.process_block_header(state, block); - }); - } + /** EPOCH PROCESSING */ @Override - public void process_randao(MutableBeaconState state, BeaconBlock block) { - callAndTrack( - "process_randao", - () -> { - super.verify_randao(state, block); - super.process_randao(state, block); - }); + public void process_justification_and_finalization(MutableBeaconState state) { + callAndTrack("process_justification_and_finalization", + () -> super.process_justification_and_finalization(state)); } @Override - public void process_eth1_data(MutableBeaconState state, BeaconBlock block) { - callAndTrack("process_eth1_data", () -> super.process_eth1_data(state, block)); + public void process_crosslinks(MutableBeaconState state) { + callAndTrack("process_crosslinks", () -> super.process_crosslinks(state)); } @Override - public List get_active_validator_indices( - ReadList validators, EpochNumber epochNumber) { - return callAndTrack( - "get_active_validator_indices", - () -> super.get_active_validator_indices(validators, epochNumber)); + public void process_rewards_and_penalties(MutableBeaconState state) { + callAndTrack("process_rewards_and_penalties", () -> super.process_rewards_and_penalties(state)); } @Override - public Gwei get_total_balance(BeaconState state, Collection validators) { - return callAndTrack("get_total_balance", () -> super.get_total_balance(state, validators)); + public List process_registry_updates(MutableBeaconState state) { + return callAndTrack("process_registry_updates", () -> super.process_registry_updates(state)); } @Override - public List get_attestation_participants( - BeaconState state, AttestationData attestation_data, Bitfield bitfield) { - return callAndTrack( - "get_attestation_participants", - () -> super.get_attestation_participants(state, attestation_data, bitfield)); + public void process_slashings(MutableBeaconState state) { + callAndTrack("process_slashings", () -> super.process_slashings(state)); } @Override - public ValidatorIndex get_validator_index_by_pubkey(BeaconState state, BLSPubkey pubkey) { - return callAndTrack( - "get_validator_index_by_pubkey", () -> super.get_validator_index_by_pubkey(state, pubkey)); + public void process_final_updates(MutableBeaconState state) { + callAndTrack("process_final_updates", () -> super.process_final_updates(state)); } + /** BLOCK PROCESSING */ + @Override - public Gwei get_previous_total_balance(BeaconState state) { - return callAndTrack( - "get_previous_total_balance", () -> super.get_previous_total_balance(state)); + public void process_block_header(MutableBeaconState state, BeaconBlock block) { + callAndTrack( + "process_block_header", + () -> { + super.verify_block_header(state, block); + super.process_block_header(state, block); + }); } @Override - public Gwei get_base_reward(BeaconState state, ValidatorIndex index) { - return callAndTrack("get_base_reward", () -> super.get_base_reward(state, index)); + public void process_randao(MutableBeaconState state, BeaconBlock block) { + callAndTrack( + "process_randao", + () -> { + super.verify_randao(state, block); + super.process_randao(state, block); + }); } @Override - public Gwei get_current_total_balance(BeaconState state) { - return callAndTrack("get_current_total_balance", () -> super.get_current_total_balance(state)); + public void process_eth1_data(MutableBeaconState state, BeaconBlock block) { + callAndTrack("process_eth1_data", () -> super.process_eth1_data(state, block)); } @Override - public boolean verify_bitfield(Bitfield bitfield, int committee_size) { - return callAndTrack("verify_bitfield", () -> super.verify_bitfield(bitfield, committee_size)); + public void process_attestation(MutableBeaconState state, Attestation attestation) { + callAndTrack( + "process_attestation", + () -> { + // count verification in benchmark measurements + super.verify_attestation(state, attestation); + super.process_attestation(state, attestation); + }); } void startTracking() { diff --git a/start/common/src/main/java/org/ethereum/beacon/util/SimulateUtils.java b/start/common/src/main/java/org/ethereum/beacon/util/SimulateUtils.java index d3eb153fe..e43161517 100644 --- a/start/common/src/main/java/org/ethereum/beacon/util/SimulateUtils.java +++ b/start/common/src/main/java/org/ethereum/beacon/util/SimulateUtils.java @@ -1,28 +1,29 @@ package org.ethereum.beacon.util; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Random; import org.ethereum.beacon.consensus.BeaconChainSpec; import org.ethereum.beacon.core.operations.Deposit; import org.ethereum.beacon.core.operations.deposit.DepositData; -import org.ethereum.beacon.core.operations.deposit.DepositInput; import org.ethereum.beacon.core.spec.SignatureDomains; -import org.ethereum.beacon.core.state.Fork; import org.ethereum.beacon.core.types.BLSPubkey; import org.ethereum.beacon.core.types.BLSSignature; -import org.ethereum.beacon.core.types.Time; import org.ethereum.beacon.crypto.BLS381; import org.ethereum.beacon.crypto.BLS381.PrivateKey; import org.ethereum.beacon.crypto.MessageParameters; import org.javatuples.Pair; 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.collections.ReadVector; import tech.pegasys.artemis.util.uint.UInt64; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Random; +import java.util.function.Function; + public class SimulateUtils { private static Pair, List> cachedDeposits = @@ -32,8 +33,8 @@ public static synchronized Pair, List> getAnyDepos Random rnd, BeaconChainSpec spec, int count, boolean isProofVerifyEnabled) { if (count > cachedDeposits.getValue0().size()) { Pair, List> newDeposits = - generateRandomDeposits(rnd, spec, count - cachedDeposits.getValue0().size(), - isProofVerifyEnabled); + generateRandomDeposits(UInt64.valueOf(cachedDeposits.getValue0().size()), rnd, spec, + count - cachedDeposits.getValue0().size(), isProofVerifyEnabled); cachedDeposits.getValue0().addAll(newDeposits.getValue0()); cachedDeposits.getValue1().addAll(newDeposits.getValue1()); } @@ -41,22 +42,21 @@ public static synchronized Pair, List> getAnyDepos cachedDeposits.getValue0().subList(0, count), cachedDeposits.getValue1().subList(0, count)); } - public static synchronized Deposit getDepositForKeyPair( - Random rnd, BLS381.KeyPair keyPair, BeaconChainSpec spec, boolean isProofVerifyEnabled) { - Hash32 proofOfPossession = Hash32.random(rnd); - DepositInput depositInputWithoutSignature = - new DepositInput( + public static synchronized Deposit getDepositForKeyPair(UInt64 depositIndex, Random rnd, + BLS381.KeyPair keyPair, BeaconChainSpec spec, boolean isProofVerifyEnabled) { + Hash32 withdrawalCredentials = Hash32.random(rnd); + DepositData depositDataWithoutSignature = + new DepositData( BLSPubkey.wrap(Bytes48.leftPad(keyPair.getPublic().getEncodedBytes())), - proofOfPossession, + withdrawalCredentials, + spec.getConstants().getMaxEffectiveBalance(), BLSSignature.wrap(Bytes96.ZERO)); BLSSignature signature = BLSSignature.ZERO; if (isProofVerifyEnabled) { - Hash32 msgHash = spec.signed_root(depositInputWithoutSignature); - UInt64 domain = - spec.get_domain( - Fork.EMPTY, spec.getConstants().getGenesisEpoch(), SignatureDomains.DEPOSIT); + Hash32 msgHash = spec.signing_root(depositDataWithoutSignature); + UInt64 domain = spec.get_domain(Bytes4.ZERO, SignatureDomains.DEPOSIT); signature = BLSSignature.wrap( BLS381.sign(MessageParameters.create(msgHash, domain), keyPair).getEncoded()); @@ -64,38 +64,38 @@ public static synchronized Deposit getDepositForKeyPair( Deposit deposit = new Deposit( - Collections.singletonList(Hash32.random(rnd)), - UInt64.ZERO, + ReadVector.wrap(Collections.singletonList(Hash32.random(rnd)), Function.identity()), + depositIndex, new DepositData( - spec.getConstants().getMaxDepositAmount(), - Time.of(0), - new DepositInput( - BLSPubkey.wrap(Bytes48.leftPad(keyPair.getPublic().getEncodedBytes())), - proofOfPossession, - signature))); + BLSPubkey.wrap(Bytes48.leftPad(keyPair.getPublic().getEncodedBytes())), + withdrawalCredentials, + spec.getConstants().getMaxEffectiveBalance(), + signature)); return deposit; } public static synchronized List getDepositsForKeyPairs( - Random rnd, List keyPairs, BeaconChainSpec spec, boolean isProofVerifyEnabled) { + UInt64 startIndex, Random rnd, List keyPairs, BeaconChainSpec spec, boolean isProofVerifyEnabled) { List deposits = new ArrayList<>(); + UInt64 index = startIndex; for (BLS381.KeyPair keyPair : keyPairs) { - deposits.add(getDepositForKeyPair(rnd, keyPair, spec, isProofVerifyEnabled)); + deposits.add(getDepositForKeyPair(index, rnd, keyPair, spec, isProofVerifyEnabled)); + index = index.increment(); } return deposits; } private static synchronized Pair, List> generateRandomDeposits( - Random rnd, BeaconChainSpec spec, int count, boolean isProofVerifyEnabled) { + UInt64 startIndex, Random rnd, BeaconChainSpec spec, int count, boolean isProofVerifyEnabled) { List validatorsKeys = new ArrayList<>(); for (int i = 0; i < count; i++) { BLS381.KeyPair keyPair = BLS381.KeyPair.create(PrivateKey.create(Bytes32.random(rnd))); validatorsKeys.add(keyPair); } - List deposits = getDepositsForKeyPairs(rnd, validatorsKeys, spec, isProofVerifyEnabled); + List deposits = getDepositsForKeyPairs(startIndex, rnd, validatorsKeys, spec, isProofVerifyEnabled); return Pair.with(deposits, validatorsKeys); } } diff --git a/start/common/src/main/resources/config/spec-constants.yml b/start/common/src/main/resources/config/spec-constants.yml index cb42e0cd5..08ddb8329 100644 --- a/start/common/src/main/resources/config/spec-constants.yml +++ b/start/common/src/main/resources/config/spec-constants.yml @@ -5,12 +5,10 @@ specConstants: honestValidatorParameters: ETH1_FOLLOW_DISTANCE: 1024 initialValues: - GENESIS_FORK_VERSION: 0 - GENESIS_SLOT: 524288 - GENESIS_START_SHARD: 0 + GENESIS_SLOT: 0 + GENESIS_EPOCH: 0 FAR_FUTURE_EPOCH: 18446744073709551615 ZERO_HASH: 0x0000000000000000000000000000000000000000000000000000000000000000 - EMPTY_SIGNATURE: 0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 BLS_WITHDRAWAL_PREFIX_BYTE: 0x00 maxOperationsPerBlock: MAX_PROPOSER_SLASHINGS: 16 @@ -18,25 +16,26 @@ specConstants: MAX_ATTESTATIONS: 128 MAX_DEPOSITS: 16 MAX_VOLUNTARY_EXITS: 16 - MAX_TRANSFERS: 16 + MAX_TRANSFERS: 0 miscParameters: SHARD_COUNT: 1024 TARGET_COMMITTEE_SIZE: 128 - MAX_BALANCE_CHURN_QUOTIENT: 32 - BEACON_CHAIN_SHARD_NUMBER: 18446744073709551615 - MAX_INDICES_PER_SLASHABLE_VOTE: 4096 - MAX_EXIT_DEQUEUES_PER_EPOCH: 4 + MAX_INDICES_PER_ATTESTATION: 4096 + MIN_PER_EPOCH_CHURN_LIMIT: 4 + CHURN_LIMIT_QUOTIENT: 65536 + BASE_REWARDS_PER_EPOCH: 5 + SHUFFLE_ROUND_COUNT: 90 gweiValues: MIN_DEPOSIT_AMOUNT: 1000000000 - MAX_DEPOSIT_AMOUNT: 32000000000 - FORK_CHOICE_BALANCE_INCREMENT: 1000000000 + MAX_EFFECTIVE_BALANCE: 32000000000 + EFFECTIVE_BALANCE_INCREMENT: 1000000000 EJECTION_BALANCE: 16000000000 rewardAndPenaltyQuotients: BASE_REWARD_QUOTIENT: 1024 - WHISTLEBLOWER_REWARD_QUOTIENT: 512 - ATTESTATION_INCLUSION_REWARD_QUOTIENT: 8 - INACTIVITY_PENALTY_QUOTIENT: 16777216 - MIN_PENALTY_QUOTIENT: 32 + WHISTLEBLOWING_REWARD_QUOTIENT: 512 + PROPOSER_REWARD_QUOTIENT: 8 + INACTIVITY_PENALTY_QUOTIENT: 33554432 + MIN_SLASHING_PENALTY_QUOTIENT: 32 stateListLengths: LATEST_RANDAO_MIXES_LENGTH: 8192 LATEST_ACTIVE_INDEX_ROOTS_LENGTH: 8192 @@ -47,6 +46,9 @@ specConstants: SLOTS_PER_EPOCH: 64 MIN_SEED_LOOKAHEAD: 1 ACTIVATION_EXIT_DELAY: 4 - EPOCHS_PER_ETH1_VOTING_PERIOD: 16 + SLOTS_PER_ETH1_VOTING_PERIOD: 1024 SLOTS_PER_HISTORICAL_ROOT: 8196 MIN_VALIDATOR_WITHDRAWABILITY_DELAY: 256 + PERSISTENT_COMMITTEE_PERIOD: 2048 + MAX_CROSSLINK_EPOCHS: 64 + MIN_EPOCHS_TO_INACTIVITY_PENALTY: 4 diff --git a/start/config/src/main/java/org/ethereum/beacon/emulator/config/chainspec/GweiValuesData.java b/start/config/src/main/java/org/ethereum/beacon/emulator/config/chainspec/GweiValuesData.java index eaa6a2efe..336703723 100644 --- a/start/config/src/main/java/org/ethereum/beacon/emulator/config/chainspec/GweiValuesData.java +++ b/start/config/src/main/java/org/ethereum/beacon/emulator/config/chainspec/GweiValuesData.java @@ -10,10 +10,10 @@ public class GweiValuesData implements GweiValues { @JsonProperty("MIN_DEPOSIT_AMOUNT") private String MIN_DEPOSIT_AMOUNT; - @JsonProperty("MAX_DEPOSIT_AMOUNT") - private String MAX_DEPOSIT_AMOUNT; - @JsonProperty("FORK_CHOICE_BALANCE_INCREMENT") - private String FORK_CHOICE_BALANCE_INCREMENT; + @JsonProperty("MAX_EFFECTIVE_BALANCE") + private String MAX_EFFECTIVE_BALANCE; + @JsonProperty("EFFECTIVE_BALANCE_INCREMENT") + private String EFFECTIVE_BALANCE_INCREMENT; @JsonProperty("EJECTION_BALANCE") private String EJECTION_BALANCE; @@ -25,14 +25,14 @@ public Gwei getMinDepositAmount() { @Override @JsonIgnore - public Gwei getMaxDepositAmount() { - return Gwei.castFrom(UInt64.valueOf(getMAX_DEPOSIT_AMOUNT())); + public Gwei getMaxEffectiveBalance() { + return Gwei.castFrom(UInt64.valueOf(getMAX_EFFECTIVE_BALANCE())); } @Override @JsonIgnore - public Gwei getForkChoiceBalanceIncrement() { - return Gwei.castFrom(UInt64.valueOf(getFORK_CHOICE_BALANCE_INCREMENT())); + public Gwei getEffectiveBalanceIncrement() { + return Gwei.castFrom(UInt64.valueOf(getEFFECTIVE_BALANCE_INCREMENT())); } @Override @@ -51,21 +51,21 @@ public void setMIN_DEPOSIT_AMOUNT(String MIN_DEPOSIT_AMOUNT) { } @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) - public String getMAX_DEPOSIT_AMOUNT() { - return MAX_DEPOSIT_AMOUNT; + public String getMAX_EFFECTIVE_BALANCE() { + return MAX_EFFECTIVE_BALANCE; } - public void setMAX_DEPOSIT_AMOUNT(String MAX_DEPOSIT_AMOUNT) { - this.MAX_DEPOSIT_AMOUNT = MAX_DEPOSIT_AMOUNT; + public void setMAX_EFFECTIVE_BALANCE(String MAX_EFFECTIVE_BALANCE) { + this.MAX_EFFECTIVE_BALANCE = MAX_EFFECTIVE_BALANCE; } @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) - public String getFORK_CHOICE_BALANCE_INCREMENT() { - return FORK_CHOICE_BALANCE_INCREMENT; + public String getEFFECTIVE_BALANCE_INCREMENT() { + return EFFECTIVE_BALANCE_INCREMENT; } - public void setFORK_CHOICE_BALANCE_INCREMENT(String FORK_CHOICE_BALANCE_INCREMENT) { - this.FORK_CHOICE_BALANCE_INCREMENT = FORK_CHOICE_BALANCE_INCREMENT; + public void setEFFECTIVE_BALANCE_INCREMENT(String EFFECTIVE_BALANCE_INCREMENT) { + this.EFFECTIVE_BALANCE_INCREMENT = EFFECTIVE_BALANCE_INCREMENT; } @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) diff --git a/start/config/src/main/java/org/ethereum/beacon/emulator/config/chainspec/InitialValuesData.java b/start/config/src/main/java/org/ethereum/beacon/emulator/config/chainspec/InitialValuesData.java index d5f7ca90f..17ca8a56e 100644 --- a/start/config/src/main/java/org/ethereum/beacon/emulator/config/chainspec/InitialValuesData.java +++ b/start/config/src/main/java/org/ethereum/beacon/emulator/config/chainspec/InitialValuesData.java @@ -5,7 +5,6 @@ import org.ethereum.beacon.core.spec.InitialValues; import org.ethereum.beacon.core.types.BLSSignature; import org.ethereum.beacon.core.types.EpochNumber; -import org.ethereum.beacon.core.types.ShardNumber; import org.ethereum.beacon.core.types.SlotNumber; import tech.pegasys.artemis.ethereum.core.Hash32; import tech.pegasys.artemis.util.bytes.Bytes1; @@ -14,27 +13,17 @@ public class InitialValuesData implements InitialValues { - @JsonProperty("GENESIS_FORK_VERSION") - private String GENESIS_FORK_VERSION; @JsonProperty("GENESIS_SLOT") private String GENESIS_SLOT; - @JsonProperty("GENESIS_START_SHARD") - private Integer GENESIS_START_SHARD; + @JsonProperty("GENESIS_EPOCH") + private String GENESIS_EPOCH; @JsonProperty("FAR_FUTURE_EPOCH") private String FAR_FUTURE_EPOCH; @JsonProperty("ZERO_HASH") private String ZERO_HASH; - @JsonProperty("EMPTY_SIGNATURE") - private String EMPTY_SIGNATURE; @JsonProperty("BLS_WITHDRAWAL_PREFIX_BYTE") private String BLS_WITHDRAWAL_PREFIX_BYTE; - @Override - @JsonIgnore - public UInt64 getGenesisForkVersion() { - return UInt64.valueOf(getGENESIS_FORK_VERSION()); - } - @Override @JsonIgnore public SlotNumber getGenesisSlot() { @@ -44,13 +33,7 @@ public SlotNumber getGenesisSlot() { @Override @JsonIgnore public EpochNumber getGenesisEpoch() { - return null;// XXX: is set in final SpecConstants construction - } - - @Override - @JsonIgnore - public ShardNumber getGenesisStartShard() { - return ShardNumber.of(getGENESIS_START_SHARD()); + return EpochNumber.castFrom(UInt64.valueOf(getGENESIS_EPOCH())); } @Override @@ -65,27 +48,12 @@ public Hash32 getZeroHash() { return Hash32.fromHexString(getZERO_HASH()); } - @Override - @JsonIgnore - public BLSSignature getEmptySignature() { - return BLSSignature.wrap(Bytes96.fromHexString(getEMPTY_SIGNATURE())); - } - @Override @JsonIgnore public Bytes1 getBlsWithdrawalPrefixByte() { return Bytes1.fromHexString(getBLS_WITHDRAWAL_PREFIX_BYTE()); } - @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) - public String getGENESIS_FORK_VERSION() { - return GENESIS_FORK_VERSION; - } - - public void setGENESIS_FORK_VERSION(String GENESIS_FORK_VERSION) { - this.GENESIS_FORK_VERSION = GENESIS_FORK_VERSION; - } - @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) public String getGENESIS_SLOT() { return GENESIS_SLOT; @@ -96,12 +64,12 @@ public void setGENESIS_SLOT(String GENESIS_SLOT) { } @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) - public Integer getGENESIS_START_SHARD() { - return GENESIS_START_SHARD; + public String getGENESIS_EPOCH() { + return GENESIS_EPOCH; } - public void setGENESIS_START_SHARD(Integer GENESIS_START_SHARD) { - this.GENESIS_START_SHARD = GENESIS_START_SHARD; + public void setGENESIS_EPOCH(String GENESIS_EPOCH) { + this.GENESIS_EPOCH = GENESIS_EPOCH; } @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) @@ -122,15 +90,6 @@ public void setZERO_HASH(String ZERO_HASH) { this.ZERO_HASH = ZERO_HASH; } - @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) - public String getEMPTY_SIGNATURE() { - return EMPTY_SIGNATURE; - } - - public void setEMPTY_SIGNATURE(String EMPTY_SIGNATURE) { - this.EMPTY_SIGNATURE = EMPTY_SIGNATURE; - } - @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) public String getBLS_WITHDRAWAL_PREFIX_BYTE() { return BLS_WITHDRAWAL_PREFIX_BYTE; diff --git a/start/config/src/main/java/org/ethereum/beacon/emulator/config/chainspec/MiscParametersData.java b/start/config/src/main/java/org/ethereum/beacon/emulator/config/chainspec/MiscParametersData.java index aa8f9ccea..2c4402bd7 100644 --- a/start/config/src/main/java/org/ethereum/beacon/emulator/config/chainspec/MiscParametersData.java +++ b/start/config/src/main/java/org/ethereum/beacon/emulator/config/chainspec/MiscParametersData.java @@ -3,7 +3,6 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import org.ethereum.beacon.core.spec.MiscParameters; -import org.ethereum.beacon.core.types.Gwei; import org.ethereum.beacon.core.types.ShardNumber; import org.ethereum.beacon.core.types.ValidatorIndex; import tech.pegasys.artemis.util.uint.UInt64; @@ -14,14 +13,16 @@ public class MiscParametersData implements MiscParameters { private String SHARD_COUNT; @JsonProperty("TARGET_COMMITTEE_SIZE") private String TARGET_COMMITTEE_SIZE; - @JsonProperty("MAX_BALANCE_CHURN_QUOTIENT") - private String MAX_BALANCE_CHURN_QUOTIENT; - @JsonProperty("BEACON_CHAIN_SHARD_NUMBER") - private String BEACON_CHAIN_SHARD_NUMBER; - @JsonProperty("MAX_INDICES_PER_SLASHABLE_VOTE") - private String MAX_INDICES_PER_SLASHABLE_VOTE; - @JsonProperty("MAX_EXIT_DEQUEUES_PER_EPOCH") - private String MAX_EXIT_DEQUEUES_PER_EPOCH; + @JsonProperty("MAX_INDICES_PER_ATTESTATION") + private String MAX_INDICES_PER_ATTESTATION; + @JsonProperty("MIN_PER_EPOCH_CHURN_LIMIT") + private String MIN_PER_EPOCH_CHURN_LIMIT; + @JsonProperty("CHURN_LIMIT_QUOTIENT") + private String CHURN_LIMIT_QUOTIENT; + @JsonProperty("BASE_REWARDS_PER_EPOCH") + private String BASE_REWARDS_PER_EPOCH; + @JsonProperty("SHUFFLE_ROUND_COUNT") + private String SHUFFLE_ROUND_COUNT; @Override @JsonIgnore @@ -37,26 +38,32 @@ public ValidatorIndex getTargetCommitteeSize() { @Override @JsonIgnore - public UInt64 getMaxBalanceChurnQuotient() { - return UInt64.valueOf(getMAX_BALANCE_CHURN_QUOTIENT()); + public UInt64 getMaxIndicesPerAttestation() { + return UInt64.valueOf(getMAX_INDICES_PER_ATTESTATION()); } @Override @JsonIgnore - public ShardNumber getBeaconChainShardNumber() { - return ShardNumber.of(UInt64.valueOf(getBEACON_CHAIN_SHARD_NUMBER())); + public UInt64 getMinPerEpochChurnLimit() { + return UInt64.valueOf(getMIN_PER_EPOCH_CHURN_LIMIT()); } @Override @JsonIgnore - public UInt64 getMaxIndicesPerSlashableVote() { - return UInt64.valueOf(getMAX_INDICES_PER_SLASHABLE_VOTE()); + public UInt64 getChurnLimitQuotient() { + return UInt64.valueOf(getCHURN_LIMIT_QUOTIENT()); } @Override @JsonIgnore - public UInt64 getMaxExitDequesPerEpoch() { - return UInt64.valueOf(getMAX_EXIT_DEQUEUES_PER_EPOCH()); + public int getShuffleRoundCount() { + return Integer.valueOf(getSHUFFLE_ROUND_COUNT()); + } + + @Override + @JsonIgnore + public UInt64 getBaseRewardsPerEpoch() { + return UInt64.valueOf(getBASE_REWARDS_PER_EPOCH()); } @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) @@ -78,38 +85,51 @@ public void setTARGET_COMMITTEE_SIZE(String TARGET_COMMITTEE_SIZE) { } @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) - public String getMAX_BALANCE_CHURN_QUOTIENT() { - return MAX_BALANCE_CHURN_QUOTIENT; + public String getMAX_INDICES_PER_ATTESTATION() { + return MAX_INDICES_PER_ATTESTATION; } - public void setMAX_BALANCE_CHURN_QUOTIENT(String MAX_BALANCE_CHURN_QUOTIENT) { - this.MAX_BALANCE_CHURN_QUOTIENT = MAX_BALANCE_CHURN_QUOTIENT; + public void setMAX_INDICES_PER_ATTESTATION(String MAX_INDICES_PER_ATTESTATION) { + this.MAX_INDICES_PER_ATTESTATION = MAX_INDICES_PER_ATTESTATION; } @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) - public String getBEACON_CHAIN_SHARD_NUMBER() { - return BEACON_CHAIN_SHARD_NUMBER; + public String getMIN_PER_EPOCH_CHURN_LIMIT() { + return MIN_PER_EPOCH_CHURN_LIMIT; } - public void setBEACON_CHAIN_SHARD_NUMBER(String BEACON_CHAIN_SHARD_NUMBER) { - this.BEACON_CHAIN_SHARD_NUMBER = BEACON_CHAIN_SHARD_NUMBER; + public void setMIN_PER_EPOCH_CHURN_LIMIT(String MIN_PER_EPOCH_CHURN_LIMIT) { + this.MIN_PER_EPOCH_CHURN_LIMIT = MIN_PER_EPOCH_CHURN_LIMIT; } @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) - public String getMAX_INDICES_PER_SLASHABLE_VOTE() { - return MAX_INDICES_PER_SLASHABLE_VOTE; + public String getCHURN_LIMIT_QUOTIENT() { + return CHURN_LIMIT_QUOTIENT; } - public void setMAX_INDICES_PER_SLASHABLE_VOTE(String MAX_INDICES_PER_SLASHABLE_VOTE) { - this.MAX_INDICES_PER_SLASHABLE_VOTE = MAX_INDICES_PER_SLASHABLE_VOTE; + public void setCHURN_LIMIT_QUOTIENT(String CHURN_LIMIT_QUOTIENT) { + this.CHURN_LIMIT_QUOTIENT = CHURN_LIMIT_QUOTIENT; } @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) - public String getMAX_EXIT_DEQUEUES_PER_EPOCH() { - return MAX_EXIT_DEQUEUES_PER_EPOCH; + public String getBASE_REWARDS_PER_EPOCH() { + return BASE_REWARDS_PER_EPOCH; + } + + public void setBASE_REWARDS_PER_EPOCH(String BASE_REWARDS_PER_EPOCH) { + this.BASE_REWARDS_PER_EPOCH = BASE_REWARDS_PER_EPOCH; + } + + @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) + public String getSHUFFLE_ROUND_COUNT() { + return SHUFFLE_ROUND_COUNT; + } + + public void setSHUFFLE_ROUND_COUNT(int SHUFFLE_ROUND_COUNT) { + this.SHUFFLE_ROUND_COUNT = String.valueOf(SHUFFLE_ROUND_COUNT); } - public void setMAX_EXIT_DEQUEUES_PER_EPOCH(String MAX_EXIT_DEQUEUES_PER_EPOCH) { - this.MAX_EXIT_DEQUEUES_PER_EPOCH = MAX_EXIT_DEQUEUES_PER_EPOCH; + public void setSHUFFLE_ROUND_COUNT(String SHUFFLE_ROUND_COUNT) { + this.SHUFFLE_ROUND_COUNT = SHUFFLE_ROUND_COUNT; } } diff --git a/start/config/src/main/java/org/ethereum/beacon/emulator/config/chainspec/RewardAndPenaltyQuotientsData.java b/start/config/src/main/java/org/ethereum/beacon/emulator/config/chainspec/RewardAndPenaltyQuotientsData.java index dec845440..e6fa35e05 100644 --- a/start/config/src/main/java/org/ethereum/beacon/emulator/config/chainspec/RewardAndPenaltyQuotientsData.java +++ b/start/config/src/main/java/org/ethereum/beacon/emulator/config/chainspec/RewardAndPenaltyQuotientsData.java @@ -9,14 +9,14 @@ public class RewardAndPenaltyQuotientsData implements RewardAndPenaltyQuotients @JsonProperty("BASE_REWARD_QUOTIENT") private String BASE_REWARD_QUOTIENT; - @JsonProperty("WHISTLEBLOWER_REWARD_QUOTIENT") - private String WHISTLEBLOWER_REWARD_QUOTIENT; - @JsonProperty("ATTESTATION_INCLUSION_REWARD_QUOTIENT") - private String ATTESTATION_INCLUSION_REWARD_QUOTIENT; + @JsonProperty("WHISTLEBLOWING_REWARD_QUOTIENT") + private String WHISTLEBLOWING_REWARD_QUOTIENT; + @JsonProperty("PROPOSER_REWARD_QUOTIENT") + private String PROPOSER_REWARD_QUOTIENT; @JsonProperty("INACTIVITY_PENALTY_QUOTIENT") private String INACTIVITY_PENALTY_QUOTIENT; - @JsonProperty("MIN_PENALTY_QUOTIENT") - private String MIN_PENALTY_QUOTIENT; + @JsonProperty("MIN_SLASHING_PENALTY_QUOTIENT") + private String MIN_SLASHING_PENALTY_QUOTIENT; @Override @JsonIgnore @@ -26,14 +26,14 @@ public UInt64 getBaseRewardQuotient() { @Override @JsonIgnore - public UInt64 getWhistleblowerRewardQuotient() { - return UInt64.valueOf(getWHISTLEBLOWER_REWARD_QUOTIENT()); + public UInt64 getWhistleblowingRewardQuotient() { + return UInt64.valueOf(getWHISTLEBLOWING_REWARD_QUOTIENT()); } @Override @JsonIgnore - public UInt64 getAttestationInclusionRewardQuotient() { - return UInt64.valueOf(getATTESTATION_INCLUSION_REWARD_QUOTIENT()); + public UInt64 getProposerRewardQuotient() { + return UInt64.valueOf(getPROPOSER_REWARD_QUOTIENT()); } @Override @@ -44,8 +44,8 @@ public UInt64 getInactivityPenaltyQuotient() { @Override @JsonIgnore - public UInt64 getMinPenaltyQuotient() { - return UInt64.valueOf(getMIN_PENALTY_QUOTIENT()); + public UInt64 getMinSlashingPenaltyQuotient() { + return UInt64.valueOf(getMIN_SLASHING_PENALTY_QUOTIENT()); } @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) @@ -58,21 +58,21 @@ public void setBASE_REWARD_QUOTIENT(String BASE_REWARD_QUOTIENT) { } @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) - public String getWHISTLEBLOWER_REWARD_QUOTIENT() { - return WHISTLEBLOWER_REWARD_QUOTIENT; + public String getWHISTLEBLOWING_REWARD_QUOTIENT() { + return WHISTLEBLOWING_REWARD_QUOTIENT; } - public void setWHISTLEBLOWER_REWARD_QUOTIENT(String WHISTLEBLOWER_REWARD_QUOTIENT) { - this.WHISTLEBLOWER_REWARD_QUOTIENT = WHISTLEBLOWER_REWARD_QUOTIENT; + public void setWHISTLEBLOWING_REWARD_QUOTIENT(String WHISTLEBLOWING_REWARD_QUOTIENT) { + this.WHISTLEBLOWING_REWARD_QUOTIENT = WHISTLEBLOWING_REWARD_QUOTIENT; } @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) - public String getATTESTATION_INCLUSION_REWARD_QUOTIENT() { - return ATTESTATION_INCLUSION_REWARD_QUOTIENT; + public String getPROPOSER_REWARD_QUOTIENT() { + return PROPOSER_REWARD_QUOTIENT; } - public void setATTESTATION_INCLUSION_REWARD_QUOTIENT(String ATTESTATION_INCLUSION_REWARD_QUOTIENT) { - this.ATTESTATION_INCLUSION_REWARD_QUOTIENT = ATTESTATION_INCLUSION_REWARD_QUOTIENT; + public void setPROPOSER_REWARD_QUOTIENT(String PROPOSER_REWARD_QUOTIENT) { + this.PROPOSER_REWARD_QUOTIENT = PROPOSER_REWARD_QUOTIENT; } @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) @@ -85,11 +85,11 @@ public void setINACTIVITY_PENALTY_QUOTIENT(String INACTIVITY_PENALTY_QUOTIENT) { } @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) - public String getMIN_PENALTY_QUOTIENT() { - return MIN_PENALTY_QUOTIENT; + public String getMIN_SLASHING_PENALTY_QUOTIENT() { + return MIN_SLASHING_PENALTY_QUOTIENT; } - public void setMIN_PENALTY_QUOTIENT(String MIN_PENALTY_QUOTIENT) { - this.MIN_PENALTY_QUOTIENT = MIN_PENALTY_QUOTIENT; + public void setMIN_SLASHING_PENALTY_QUOTIENT(String MIN_SLASHING_PENALTY_QUOTIENT) { + this.MIN_SLASHING_PENALTY_QUOTIENT = MIN_SLASHING_PENALTY_QUOTIENT; } } diff --git a/start/config/src/main/java/org/ethereum/beacon/emulator/config/chainspec/SpecBuilder.java b/start/config/src/main/java/org/ethereum/beacon/emulator/config/chainspec/SpecBuilder.java index 53a2c2a11..7436e338d 100644 --- a/start/config/src/main/java/org/ethereum/beacon/emulator/config/chainspec/SpecBuilder.java +++ b/start/config/src/main/java/org/ethereum/beacon/emulator/config/chainspec/SpecBuilder.java @@ -82,18 +82,18 @@ public Gwei getMinDepositAmount() { } @Override - public Gwei getMaxDepositAmount() { - return gweiValues.getMaxDepositAmount(); + public Gwei getMaxEffectiveBalance() { + return gweiValues.getMaxEffectiveBalance(); } @Override - public Gwei getForkChoiceBalanceIncrement() { - return gweiValues.getForkChoiceBalanceIncrement(); + public Gwei getEffectiveBalanceIncrement() { + return gweiValues.getEffectiveBalanceIncrement(); } @Override - public UInt64 getMinPenaltyQuotient() { - return rewardAndPenaltyQuotients.getMinPenaltyQuotient(); + public UInt64 getMinSlashingPenaltyQuotient() { + return rewardAndPenaltyQuotients.getMinSlashingPenaltyQuotient(); } @Override @@ -101,21 +101,11 @@ public long getEth1FollowDistance() { return honestValidatorParameters.getEth1FollowDistance(); } - @Override - public UInt64 getGenesisForkVersion() { - return initialValues.getGenesisForkVersion(); - } - @Override public SlotNumber getGenesisSlot() { return initialValues.getGenesisSlot(); } - @Override - public ShardNumber getGenesisStartShard() { - return initialValues.getGenesisStartShard(); - } - @Override public EpochNumber getFarFutureEpoch() { return initialValues.getFarFutureEpoch(); @@ -126,11 +116,6 @@ public Hash32 getZeroHash() { return initialValues.getZeroHash(); } - @Override - public BLSSignature getEmptySignature() { - return initialValues.getEmptySignature(); - } - @Override public Bytes1 getBlsWithdrawalPrefixByte() { return initialValues.getBlsWithdrawalPrefixByte(); @@ -177,23 +162,23 @@ public Gwei getEjectionBalance() { } @Override - public UInt64 getMaxBalanceChurnQuotient() { - return miscParameters.getMaxBalanceChurnQuotient(); + public UInt64 getMaxIndicesPerAttestation() { + return miscParameters.getMaxIndicesPerAttestation(); } @Override - public ShardNumber getBeaconChainShardNumber() { - return miscParameters.getBeaconChainShardNumber(); + public UInt64 getMinPerEpochChurnLimit() { + return miscParameters.getMinPerEpochChurnLimit(); } @Override - public UInt64 getMaxIndicesPerSlashableVote() { - return miscParameters.getMaxIndicesPerSlashableVote(); + public UInt64 getChurnLimitQuotient() { + return miscParameters.getChurnLimitQuotient(); } @Override - public UInt64 getMaxExitDequesPerEpoch() { - return miscParameters.getMaxExitDequesPerEpoch(); + public UInt64 getBaseRewardsPerEpoch() { + return miscParameters.getBaseRewardsPerEpoch(); } @Override @@ -202,13 +187,13 @@ public UInt64 getBaseRewardQuotient() { } @Override - public UInt64 getWhistleblowerRewardQuotient() { - return rewardAndPenaltyQuotients.getWhistleblowerRewardQuotient(); + public UInt64 getWhistleblowingRewardQuotient() { + return rewardAndPenaltyQuotients.getWhistleblowingRewardQuotient(); } @Override - public UInt64 getAttestationInclusionRewardQuotient() { - return rewardAndPenaltyQuotients.getAttestationInclusionRewardQuotient(); + public UInt64 getProposerRewardQuotient() { + return rewardAndPenaltyQuotients.getProposerRewardQuotient(); } @Override @@ -257,8 +242,8 @@ public EpochNumber getActivationExitDelay() { } @Override - public EpochNumber getEpochsPerEth1VotingPeriod() { - return timeParameters.getEpochsPerEth1VotingPeriod(); + public EpochNumber getSlotsPerEth1VotingPeriod() { + return timeParameters.getSlotsPerEth1VotingPeriod(); } @Override @@ -267,11 +252,39 @@ public EpochNumber getMinValidatorWithdrawabilityDelay() { } @Override - public SlotNumber getSlotsPerHistoricalRoot() { - return timeParameters.getSlotsPerHistoricalRoot(); + public EpochNumber getGenesisEpoch() { + return initialValues.getGenesisEpoch(); } + @Override + public int getMaxTransfers() { + return maxOperationsPerBlock.getMaxTransfers(); + } + @Override + public int getShuffleRoundCount() { + return miscParameters.getShuffleRoundCount(); + } + + @Override + public EpochNumber getPersistentCommitteePeriod() { + return timeParameters.getPersistentCommitteePeriod(); + } + + @Override + public EpochNumber getMaxCrosslinkEpochs() { + return timeParameters.getMaxCrosslinkEpochs(); + } + + @Override + public EpochNumber getMinEpochsToInactivityPenalty() { + return timeParameters.getMinEpochsToInactivityPenalty(); + } + + @Override + public SlotNumber getSlotsPerHistoricalRoot() { + return timeParameters.getSlotsPerHistoricalRoot(); + } }; } diff --git a/start/config/src/main/java/org/ethereum/beacon/emulator/config/chainspec/SpecDataUtils.java b/start/config/src/main/java/org/ethereum/beacon/emulator/config/chainspec/SpecDataUtils.java index e14f9b44a..7786dd87f 100644 --- a/start/config/src/main/java/org/ethereum/beacon/emulator/config/chainspec/SpecDataUtils.java +++ b/start/config/src/main/java/org/ethereum/beacon/emulator/config/chainspec/SpecDataUtils.java @@ -27,11 +27,8 @@ public static SpecConstantsData createSpecConstantsData(SpecConstants constants) new InitialValuesData() { { setBLS_WITHDRAWAL_PREFIX_BYTE(constants.getBlsWithdrawalPrefixByte().toString()); - setEMPTY_SIGNATURE(constants.getEmptySignature().copy().toString()); setFAR_FUTURE_EPOCH(constants.getFarFutureEpoch().toString()); - setGENESIS_FORK_VERSION(constants.getGenesisForkVersion().toString()); setGENESIS_SLOT(Long.toUnsignedString(constants.getGenesisSlot().getValue())); - setGENESIS_START_SHARD(constants.getGenesisStartShard().intValue()); setZERO_HASH(constants.getZeroHash().toString()); } }; @@ -51,12 +48,13 @@ public static SpecConstantsData createSpecConstantsData(SpecConstants constants) MiscParametersData miscParameters = new MiscParametersData() { { - setBEACON_CHAIN_SHARD_NUMBER(constants.getBeaconChainShardNumber().toString()); - setMAX_BALANCE_CHURN_QUOTIENT(constants.getMaxBalanceChurnQuotient().toString()); - setMAX_INDICES_PER_SLASHABLE_VOTE(constants.getMaxIndicesPerSlashableVote().toString()); + setMAX_INDICES_PER_ATTESTATION(constants.getMaxIndicesPerAttestation().toString()); + setMIN_PER_EPOCH_CHURN_LIMIT(constants.getMinPerEpochChurnLimit().toString()); + setCHURN_LIMIT_QUOTIENT(constants.getChurnLimitQuotient().toString()); setSHARD_COUNT(constants.getShardCount().toString()); setTARGET_COMMITTEE_SIZE(constants.getTargetCommitteeSize().toString()); - setMAX_EXIT_DEQUEUES_PER_EPOCH(constants.getMaxExitDequesPerEpoch().toString()); + setBASE_REWARDS_PER_EPOCH(constants.getBaseRewardsPerEpoch().toString()); + setSHUFFLE_ROUND_COUNT(constants.getShuffleRoundCount()); } }; @@ -64,12 +62,12 @@ public static SpecConstantsData createSpecConstantsData(SpecConstants constants) new GweiValuesData() { { setEJECTION_BALANCE(Long.toUnsignedString(constants.getEjectionBalance().getValue())); - setFORK_CHOICE_BALANCE_INCREMENT( - Long.toUnsignedString(constants.getForkChoiceBalanceIncrement().getValue())); + setEFFECTIVE_BALANCE_INCREMENT( + Long.toUnsignedString(constants.getEffectiveBalanceIncrement().getValue())); setMIN_DEPOSIT_AMOUNT( Long.toUnsignedString(constants.getMinDepositAmount().getValue())); - setMAX_DEPOSIT_AMOUNT( - Long.toUnsignedString(constants.getMaxDepositAmount().getValue())); + setMAX_EFFECTIVE_BALANCE( + Long.toUnsignedString(constants.getMaxEffectiveBalance().getValue())); } }; @@ -78,10 +76,10 @@ public static SpecConstantsData createSpecConstantsData(SpecConstants constants) { setBASE_REWARD_QUOTIENT(constants.getBaseRewardQuotient().toString()); setINACTIVITY_PENALTY_QUOTIENT(constants.getInactivityPenaltyQuotient().toString()); - setWHISTLEBLOWER_REWARD_QUOTIENT(constants.getWhistleblowerRewardQuotient().toString()); - setATTESTATION_INCLUSION_REWARD_QUOTIENT( - constants.getAttestationInclusionRewardQuotient().toString()); - setMIN_PENALTY_QUOTIENT(constants.getMinPenaltyQuotient().toString()); + setWHISTLEBLOWING_REWARD_QUOTIENT(constants.getWhistleblowingRewardQuotient().toString()); + setPROPOSER_REWARD_QUOTIENT( + constants.getProposerRewardQuotient().toString()); + setMIN_SLASHING_PENALTY_QUOTIENT(constants.getMinSlashingPenaltyQuotient().toString()); } }; @@ -101,13 +99,14 @@ public static SpecConstantsData createSpecConstantsData(SpecConstants constants) setMIN_ATTESTATION_INCLUSION_DELAY( Long.toUnsignedString(constants.getMinAttestationInclusionDelay().getValue())); setACTIVATION_EXIT_DELAY(constants.getActivationExitDelay().toString()); - setEPOCHS_PER_ETH1_VOTING_PERIOD(constants.getEpochsPerEth1VotingPeriod().toString()); + setSLOTS_PER_ETH1_VOTING_PERIOD(constants.getSlotsPerEth1VotingPeriod().toString()); setMIN_SEED_LOOKAHEAD(constants.getMinSeedLookahead().toString()); setMIN_VALIDATOR_WITHDRAWABILITY_DELAY( constants.getMinValidatorWithdrawabilityDelay().toString()); setSECONDS_PER_SLOT(Long.toString(constants.getSecondsPerSlot().getValue())); setSLOTS_PER_EPOCH(Long.toUnsignedString(constants.getSlotsPerEpoch().getValue())); setPERSISTENT_COMMITTEE_PERIOD(constants.getPersistentCommitteePeriod().toString()); + setMAX_CROSSLINK_EPOCHS(constants.getMaxCrosslinkEpochs().toString()); setSLOTS_PER_HISTORICAL_ROOT( Long.toUnsignedString(constants.getSlotsPerHistoricalRoot().getValue())); } diff --git a/start/config/src/main/java/org/ethereum/beacon/emulator/config/chainspec/TimeParametersData.java b/start/config/src/main/java/org/ethereum/beacon/emulator/config/chainspec/TimeParametersData.java index d589c5e3e..d2a184d3b 100644 --- a/start/config/src/main/java/org/ethereum/beacon/emulator/config/chainspec/TimeParametersData.java +++ b/start/config/src/main/java/org/ethereum/beacon/emulator/config/chainspec/TimeParametersData.java @@ -21,14 +21,18 @@ public class TimeParametersData implements TimeParameters { private String MIN_SEED_LOOKAHEAD; @JsonProperty("ACTIVATION_EXIT_DELAY") private String ACTIVATION_EXIT_DELAY; - @JsonProperty("EPOCHS_PER_ETH1_VOTING_PERIOD") - private String EPOCHS_PER_ETH1_VOTING_PERIOD; + @JsonProperty("SLOTS_PER_ETH1_VOTING_PERIOD") + private String SLOTS_PER_ETH1_VOTING_PERIOD; @JsonProperty("SLOTS_PER_HISTORICAL_ROOT") private String SLOTS_PER_HISTORICAL_ROOT; @JsonProperty("MIN_VALIDATOR_WITHDRAWABILITY_DELAY") private String MIN_VALIDATOR_WITHDRAWABILITY_DELAY; @JsonProperty("PERSISTENT_COMMITTEE_PERIOD") private String PERSISTENT_COMMITTEE_PERIOD; + @JsonProperty("MAX_CROSSLINK_EPOCHS") + private String MAX_CROSSLINK_EPOCHS; + @JsonProperty("MIN_EPOCHS_TO_INACTIVITY_PENALTY") + private String MIN_EPOCHS_TO_INACTIVITY_PENALTY; @Override @JsonIgnore @@ -62,8 +66,8 @@ public EpochNumber getActivationExitDelay() { @Override @JsonIgnore - public EpochNumber getEpochsPerEth1VotingPeriod() { - return new EpochNumber(UInt64.valueOf(getEPOCHS_PER_ETH1_VOTING_PERIOD())); + public EpochNumber getSlotsPerEth1VotingPeriod() { + return new EpochNumber(UInt64.valueOf(getSLOTS_PER_ETH1_VOTING_PERIOD())); } @Override @@ -84,6 +88,18 @@ public EpochNumber getPersistentCommitteePeriod() { return new EpochNumber(UInt64.valueOf(getPERSISTENT_COMMITTEE_PERIOD())); } + @Override + @JsonIgnore + public EpochNumber getMaxCrosslinkEpochs() { + return new EpochNumber(UInt64.valueOf(getMAX_CROSSLINK_EPOCHS())); + } + + @Override + @JsonIgnore + public EpochNumber getMinEpochsToInactivityPenalty() { + return new EpochNumber(UInt64.valueOf(getMIN_EPOCHS_TO_INACTIVITY_PENALTY())); + } + @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) public String getSECONDS_PER_SLOT() { return SECONDS_PER_SLOT; @@ -130,12 +146,12 @@ public void setACTIVATION_EXIT_DELAY(String ACTIVATION_EXIT_DELAY) { } @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) - public String getEPOCHS_PER_ETH1_VOTING_PERIOD() { - return EPOCHS_PER_ETH1_VOTING_PERIOD; + public String getSLOTS_PER_ETH1_VOTING_PERIOD() { + return SLOTS_PER_ETH1_VOTING_PERIOD; } - public void setEPOCHS_PER_ETH1_VOTING_PERIOD(String EPOCHS_PER_ETH1_VOTING_PERIOD) { - this.EPOCHS_PER_ETH1_VOTING_PERIOD = EPOCHS_PER_ETH1_VOTING_PERIOD; + public void setSLOTS_PER_ETH1_VOTING_PERIOD(String SLOTS_PER_ETH1_VOTING_PERIOD) { + this.SLOTS_PER_ETH1_VOTING_PERIOD = SLOTS_PER_ETH1_VOTING_PERIOD; } @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) @@ -156,6 +172,7 @@ public void setMIN_VALIDATOR_WITHDRAWABILITY_DELAY(String MIN_VALIDATOR_WITHDRAW this.MIN_VALIDATOR_WITHDRAWABILITY_DELAY = MIN_VALIDATOR_WITHDRAWABILITY_DELAY; } + @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) public String getPERSISTENT_COMMITTEE_PERIOD() { return PERSISTENT_COMMITTEE_PERIOD; } @@ -163,4 +180,22 @@ public String getPERSISTENT_COMMITTEE_PERIOD() { public void setPERSISTENT_COMMITTEE_PERIOD(String PERSISTENT_COMMITTEE_PERIOD) { this.PERSISTENT_COMMITTEE_PERIOD = PERSISTENT_COMMITTEE_PERIOD; } + + @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) + public String getMAX_CROSSLINK_EPOCHS() { + return MAX_CROSSLINK_EPOCHS; + } + + public void setMAX_CROSSLINK_EPOCHS(String MAX_CROSSLINK_EPOCHS) { + this.MAX_CROSSLINK_EPOCHS = MAX_CROSSLINK_EPOCHS; + } + + @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) + public String getMIN_EPOCHS_TO_INACTIVITY_PENALTY() { + return MIN_EPOCHS_TO_INACTIVITY_PENALTY; + } + + public void setMIN_EPOCHS_TO_INACTIVITY_PENALTY(String MIN_EPOCHS_TO_INACTIVITY_PENALTY) { + this.MIN_EPOCHS_TO_INACTIVITY_PENALTY = MIN_EPOCHS_TO_INACTIVITY_PENALTY; + } } diff --git a/start/config/src/test/java/org/ethereum/beacon/emulator/config/ConfigBuilderTest.java b/start/config/src/test/java/org/ethereum/beacon/emulator/config/ConfigBuilderTest.java index 5560b3b69..cfeaaa8f0 100644 --- a/start/config/src/test/java/org/ethereum/beacon/emulator/config/ConfigBuilderTest.java +++ b/start/config/src/test/java/org/ethereum/beacon/emulator/config/ConfigBuilderTest.java @@ -68,7 +68,6 @@ public void testChainSpec() { SpecConstants specConstantsDefault = BeaconChainSpec.DEFAULT_CONSTANTS; assertEquals(specConstantsDefault.getGenesisEpoch(), specConstants.getGenesisEpoch()); - assertEquals(specConstantsDefault.getEmptySignature(), specConstants.getEmptySignature()); assertEquals(specConstantsDefault.getSlotsPerEpoch(), specConstants.getSlotsPerEpoch()); assertEquals(specConstantsDefault.getSecondsPerSlot(), specConstants.getSecondsPerSlot()); diff --git a/start/config/src/test/resources/chainSpec.yml b/start/config/src/test/resources/chainSpec.yml index cda6704ec..08ddb8329 100644 --- a/start/config/src/test/resources/chainSpec.yml +++ b/start/config/src/test/resources/chainSpec.yml @@ -5,12 +5,10 @@ specConstants: honestValidatorParameters: ETH1_FOLLOW_DISTANCE: 1024 initialValues: - GENESIS_FORK_VERSION: 0 - GENESIS_SLOT: 4294967296 - GENESIS_START_SHARD: 0 + GENESIS_SLOT: 0 + GENESIS_EPOCH: 0 FAR_FUTURE_EPOCH: 18446744073709551615 ZERO_HASH: 0x0000000000000000000000000000000000000000000000000000000000000000 - EMPTY_SIGNATURE: 0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 BLS_WITHDRAWAL_PREFIX_BYTE: 0x00 maxOperationsPerBlock: MAX_PROPOSER_SLASHINGS: 16 @@ -18,25 +16,26 @@ specConstants: MAX_ATTESTATIONS: 128 MAX_DEPOSITS: 16 MAX_VOLUNTARY_EXITS: 16 - MAX_TRANSFERS: 16 + MAX_TRANSFERS: 0 miscParameters: SHARD_COUNT: 1024 TARGET_COMMITTEE_SIZE: 128 - MAX_BALANCE_CHURN_QUOTIENT: 32 - BEACON_CHAIN_SHARD_NUMBER: 18446744073709551615 - MAX_INDICES_PER_SLASHABLE_VOTE: 4096 - MAX_EXIT_DEQUEUES_PER_EPOCH: 4 + MAX_INDICES_PER_ATTESTATION: 4096 + MIN_PER_EPOCH_CHURN_LIMIT: 4 + CHURN_LIMIT_QUOTIENT: 65536 + BASE_REWARDS_PER_EPOCH: 5 + SHUFFLE_ROUND_COUNT: 90 gweiValues: MIN_DEPOSIT_AMOUNT: 1000000000 - MAX_DEPOSIT_AMOUNT: 32000000000 - FORK_CHOICE_BALANCE_INCREMENT: 1000000000 + MAX_EFFECTIVE_BALANCE: 32000000000 + EFFECTIVE_BALANCE_INCREMENT: 1000000000 EJECTION_BALANCE: 16000000000 rewardAndPenaltyQuotients: BASE_REWARD_QUOTIENT: 1024 - WHISTLEBLOWER_REWARD_QUOTIENT: 512 - ATTESTATION_INCLUSION_REWARD_QUOTIENT: 8 - INACTIVITY_PENALTY_QUOTIENT: 16777216 - MIN_PENALTY_QUOTIENT: 32 + WHISTLEBLOWING_REWARD_QUOTIENT: 512 + PROPOSER_REWARD_QUOTIENT: 8 + INACTIVITY_PENALTY_QUOTIENT: 33554432 + MIN_SLASHING_PENALTY_QUOTIENT: 32 stateListLengths: LATEST_RANDAO_MIXES_LENGTH: 8192 LATEST_ACTIVE_INDEX_ROOTS_LENGTH: 8192 @@ -47,7 +46,9 @@ specConstants: SLOTS_PER_EPOCH: 64 MIN_SEED_LOOKAHEAD: 1 ACTIVATION_EXIT_DELAY: 4 - EPOCHS_PER_ETH1_VOTING_PERIOD: 16 + SLOTS_PER_ETH1_VOTING_PERIOD: 1024 SLOTS_PER_HISTORICAL_ROOT: 8196 MIN_VALIDATOR_WITHDRAWABILITY_DELAY: 256 PERSISTENT_COMMITTEE_PERIOD: 2048 + MAX_CROSSLINK_EPOCHS: 64 + MIN_EPOCHS_TO_INACTIVITY_PENALTY: 4 diff --git a/start/simulator/src/main/java/org/ethereum/beacon/simulator/SimulatorLauncher.java b/start/simulator/src/main/java/org/ethereum/beacon/simulator/SimulatorLauncher.java index bc6370707..ab81ee2ce 100644 --- a/start/simulator/src/main/java/org/ethereum/beacon/simulator/SimulatorLauncher.java +++ b/start/simulator/src/main/java/org/ethereum/beacon/simulator/SimulatorLauncher.java @@ -61,6 +61,7 @@ import reactor.core.publisher.Mono; import tech.pegasys.artemis.ethereum.core.Hash32; import tech.pegasys.artemis.util.bytes.Bytes32; +import tech.pegasys.artemis.util.uint.UInt64; public class SimulatorLauncher implements Runnable { private static final Logger logger = LogManager.getLogger("simulator"); @@ -127,7 +128,8 @@ private Pair, List> getValidatorDeposits(Random rn if (validators.get(i).getBlsPrivateKey() != null) { KeyPair keyPair = KeyPair.create( PrivateKey.create(Bytes32.fromHexString(validators.get(i).getBlsPrivateKey()))); - deposits.getValue0().set(i, SimulateUtils.getDepositForKeyPair(rnd, keyPair, spec, + Deposit deposit = deposits.getValue0().get(i); + deposits.getValue0().set(i, SimulateUtils.getDepositForKeyPair(deposit.getIndex(), rnd, keyPair, spec, config.getChainSpec().getSpecHelpersOptions().isBlsVerifyProofOfPossession())); deposits.getValue1().set(i, keyPair); } @@ -154,7 +156,7 @@ public void run() { MDCControlledSchedulers controlledSchedulers = new MDCControlledSchedulers(); controlledSchedulers.setCurrentTime(genesisTime.getMillis().getValue() + 1000); - Eth1Data eth1Data = new Eth1Data(Hash32.random(rnd), Hash32.random(rnd)); + Eth1Data eth1Data = new Eth1Data(Hash32.random(rnd), UInt64.ZERO, Hash32.random(rnd)); LocalWireHub localWireHub = new LocalWireHub(s -> wire.trace(s), controlledSchedulers.createNew("wire")); @@ -231,11 +233,11 @@ public void run() { }); Flux.from(launcher.getBeaconChain().getBlockStatesStream()) .subscribe(blockState -> logger.trace("Block imported: " - + blockState.getBlock().toString(this.specConstants, genesisTime, spec::signed_root))); + + blockState.getBlock().toString(this.specConstants, genesisTime, spec::signing_root))); if (launcher.getValidatorService() != null) { Flux.from(launcher.getValidatorService().getProposedBlocksStream()) .subscribe(block -> logger.debug("New block created: " - + block.toString(this.specConstants, genesisTime, spec::signed_root))); + + block.toString(this.specConstants, genesisTime, spec::signing_root))); Flux.from(launcher.getValidatorService().getAttestationsStream()) .subscribe(attest -> logger.debug("New attestation created: " + attest.toString(this.specConstants, genesisTime))); @@ -282,7 +284,7 @@ public void run() { .subscribe(blockState -> { blocks.add(blockState.getBlock()); logger.debug("Block imported: " - + blockState.getBlock().toString(specConstants, genesisTime, spec::signed_root)); + + blockState.getBlock().toString(specConstants, genesisTime, spec::signing_root)); }); logger.info("Time starts running ..."); diff --git a/start/simulator/src/main/resources/config/default-simulation-config.yml b/start/simulator/src/main/resources/config/default-simulation-config.yml index 10911a81d..6b341c67e 100644 --- a/start/simulator/src/main/resources/config/default-simulation-config.yml +++ b/start/simulator/src/main/resources/config/default-simulation-config.yml @@ -12,8 +12,6 @@ plan: !simulation chainSpec: specConstants: - initialValues: - GENESIS_SLOT: 1000000 miscParameters: SHARD_COUNT: 4 TARGET_COMMITTEE_SIZE: 2 diff --git a/start/simulator/src/test/resources/config/fast-chainSpec.yml b/start/simulator/src/test/resources/config/fast-chainSpec.yml index 94ef0349f..92d6390ca 100644 --- a/start/simulator/src/test/resources/config/fast-chainSpec.yml +++ b/start/simulator/src/test/resources/config/fast-chainSpec.yml @@ -1,5 +1,5 @@ initialValues: - GENESIS_SLOT: 1000000 + GENESIS_SLOT: 0 miscParameters: TARGET_COMMITTEE_SIZE: 1 timeParameters: diff --git a/test/src/test/java/org/ethereum/beacon/test/BlsTests.java b/test/src/test/java/org/ethereum/beacon/test/BlsTests.java index 83557d226..b29a49e60 100644 --- a/test/src/test/java/org/ethereum/beacon/test/BlsTests.java +++ b/test/src/test/java/org/ethereum/beacon/test/BlsTests.java @@ -18,6 +18,7 @@ import static org.junit.Assert.fail; +@Ignore public class BlsTests extends TestUtils { private String TESTS_DIR = "bls"; private String FILENAME = "test_bls.yml"; diff --git a/test/src/test/java/org/ethereum/beacon/test/ShuffleTests.java b/test/src/test/java/org/ethereum/beacon/test/ShuffleTests.java index 821ecfc35..a1ec17e95 100644 --- a/test/src/test/java/org/ethereum/beacon/test/ShuffleTests.java +++ b/test/src/test/java/org/ethereum/beacon/test/ShuffleTests.java @@ -58,41 +58,39 @@ public EpochNumber getActivationExitDelay() { @Test public void testShuffling() { - Path sszTestsPath = Paths.get(PATH_TO_TESTS, TESTS_DIR); - runTestsInResourceDir( - sszTestsPath, - ShuffleTest.class, - testCase -> { - ShuffleRunner testCaseRunner = - new ShuffleRunner( - testCase, - spec, - objects -> - spec.get_shuffling( - objects.getValue0(), objects.getValue1(), objects.getValue2())); - return testCaseRunner.run(); - }); + // TODO wait until tests are updated to v0.6.0 +// Path sszTestsPath = Paths.get(PATH_TO_TESTS, TESTS_DIR); +// runTestsInResourceDir( +// sszTestsPath, +// ShuffleTest.class, +// testCase -> { +// ShuffleRunner testCaseRunner = +// new ShuffleRunner( +// testCase, +// spec, +// objects -> +// spec.get_shuffling( +// objects.getValue0(), objects.getValue1(), objects.getValue2())); +// return testCaseRunner.run(); +// }); } - /** - * Runs tests on optimized version of get_shuffling, {@link BeaconChainSpec#get_shuffling2(Hash32, - * ReadList, EpochNumber)} - */ @Test public void testShuffling2() { - Path sszTestsPath = Paths.get(PATH_TO_TESTS, TESTS_DIR); - runTestsInResourceDir( - sszTestsPath, - ShuffleTest.class, - testCase -> { - ShuffleRunner testCaseRunner = - new ShuffleRunner( - testCase, - spec, - objects -> - spec.get_shuffling2( - objects.getValue0(), objects.getValue1(), objects.getValue2())); - return testCaseRunner.run(); - }); + // TODO wait until tests are updated to v0.6.0 +// Path sszTestsPath = Paths.get(PATH_TO_TESTS, TESTS_DIR); +// runTestsInResourceDir( +// sszTestsPath, +// ShuffleTest.class, +// testCase -> { +// ShuffleRunner testCaseRunner = +// new ShuffleRunner( +// testCase, +// spec, +// objects -> +// spec.get_shuffling2( +// objects.getValue0(), objects.getValue1(), objects.getValue2())); +// return testCaseRunner.run(); +// }); } } diff --git a/test/src/test/java/org/ethereum/beacon/test/StateTestUtils.java b/test/src/test/java/org/ethereum/beacon/test/StateTestUtils.java index 706089650..d31173c13 100644 --- a/test/src/test/java/org/ethereum/beacon/test/StateTestUtils.java +++ b/test/src/test/java/org/ethereum/beacon/test/StateTestUtils.java @@ -17,9 +17,8 @@ import org.ethereum.beacon.core.operations.attestation.AttestationData; import org.ethereum.beacon.core.operations.attestation.Crosslink; import org.ethereum.beacon.core.operations.deposit.DepositData; -import org.ethereum.beacon.core.operations.deposit.DepositInput; import org.ethereum.beacon.core.operations.slashing.AttesterSlashing; -import org.ethereum.beacon.core.operations.slashing.SlashableAttestation; +import org.ethereum.beacon.core.operations.slashing.IndexedAttestation; import org.ethereum.beacon.core.spec.SpecConstants; import org.ethereum.beacon.core.state.Eth1Data; import org.ethereum.beacon.core.state.Fork; @@ -46,9 +45,11 @@ import org.ethereum.beacon.test.type.state.StateTestCase.BlockData.BlockBodyData.SlashableAttestationData; import org.javatuples.Pair; 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.Bytes96; import tech.pegasys.artemis.util.bytes.BytesValue; +import tech.pegasys.artemis.util.collections.ReadVector; import tech.pegasys.artemis.util.uint.UInt64; /** Various utility methods aiding state tests development. */ @@ -57,29 +58,13 @@ private StateTestUtils() {} public static Pair> parseBlockData( StateTestCase.BlockData blockData) { - Eth1Data eth1Data1 = - new Eth1Data( - Hash32.fromHexString(blockData.getBody().getEth1Data().getDepositRoot()), - Hash32.fromHexString(blockData.getBody().getEth1Data().getBlockHash())); + Eth1Data eth1Data1 = parseEth1Data(blockData.getBody().getEth1Data()); // Attestations List attestations = new ArrayList<>(); for (StateTestCase.BeaconStateData.AttestationData attestationData : blockData.getBody().getAttestations()) { - AttestationData attestationData1 = - new AttestationData( - SlotNumber.castFrom(UInt64.valueOf(attestationData.getData().getSlot())), - Hash32.fromHexString(attestationData.getData().getBeaconBlockRoot()), - EpochNumber.castFrom(UInt64.valueOf(attestationData.getData().getSourceEpoch())), - Hash32.fromHexString(attestationData.getData().getSourceRoot()), - Hash32.fromHexString(attestationData.getData().getTargetRoot()), - ShardNumber.of(attestationData.getData().getShard()), - new Crosslink( - EpochNumber.castFrom( - UInt64.valueOf(attestationData.getData().getPreviousCrosslink().getEpoch())), - Hash32.fromHexString( - attestationData.getData().getPreviousCrosslink().getCrosslinkDataRoot())), - Hash32.fromHexString(attestationData.getData().getCrosslinkDataRoot())); + AttestationData attestationData1 = parseAttestationData(attestationData.getData()); Attestation attestation = new Attestation( Bitfield.of(BytesValue.fromHexString(attestationData.getAggregationBitfield())), @@ -103,27 +88,16 @@ public static Pair> parseBlockData( blockData.getBody().getDeposits()) { Deposit deposit = new Deposit( - depositData.getProof().stream() + ReadVector.wrap(depositData.getProof().stream() .map(Hash32::fromHexString) - .collect(Collectors.toList()), + .collect(Collectors.toList()), Integer::new), UInt64.valueOf(depositData.getIndex()), new DepositData( + BLSPubkey.fromHexString(depositData.getDepositData().getPubkey()), + Hash32.fromHexString(depositData.getDepositData().getWithdrawalCredentials()), Gwei.castFrom(UInt64.valueOf(depositData.getDepositData().getAmount())), - Time.of(depositData.getDepositData().getTimestamp()), - new DepositInput( - BLSPubkey.fromHexString( - depositData.getDepositData().getDepositInput().getPubkey()), - Hash32.fromHexString( - depositData - .getDepositData() - .getDepositInput() - .getWithdrawalCredentials()), - BLSSignature.wrap( - Bytes96.fromHexString( - depositData - .getDepositData() - .getDepositInput() - .getProofOfPossession()))))); + BLSSignature.wrap( + Bytes96.fromHexString(depositData.getDepositData().getSignature())))); deposits.add(deposit); } @@ -180,9 +154,10 @@ public static Pair> parseBlockData( // Finally, creating a block BeaconBlockBody blockBody = - new BeaconBlockBody( + BeaconBlockBody.create( BLSSignature.wrap(Bytes96.fromHexString(blockData.getBody().getRandaoReveal())), eth1Data1, + Bytes32.ZERO, proposerSlashings, attesterSlashings, attestations, @@ -200,11 +175,11 @@ public static Pair> parseBlockData( return Pair.with(block, Optional.empty()); } - public static SlashableAttestation parseSlashableAttestation(SlashableAttestationData data) { - return new SlashableAttestation( - data.getValidatorIndices().stream().map(ValidatorIndex::of).collect(Collectors.toList()), + public static IndexedAttestation parseSlashableAttestation(SlashableAttestationData data) { + return new IndexedAttestation( + data.getCustodyBit0Indices().stream().map(ValidatorIndex::of).collect(Collectors.toList()), + data.getCustodyBit1Indices().stream().map(ValidatorIndex::of).collect(Collectors.toList()), parseAttestationData(data.getData()), - Bitfield.of(BytesValue.fromHexString(data.getCustodyBitfield())), data.getAggregateSignature() != null ? BLSSignature.wrap(Bytes96.fromHexString(data.getAggregateSignature())) : BLSSignature.ZERO); @@ -216,16 +191,6 @@ public static MutableBeaconState parseBeaconState(SpecConstants specConstants, B state.setSlot(SlotNumber.castFrom(UInt64.valueOf(data.getSlot()))); state.setGenesisTime(Time.of(data.getGenesisTime())); state.setFork(parseFork(data.getFork())); - state.setValidatorRegistryUpdateEpoch( - EpochNumber.castFrom(UInt64.valueOf(data.getValidatorRegistryUpdateEpoch()))); - state.setPreviousShufflingStartShard(ShardNumber.of(data.getPreviousShufflingStartShard())); - state.setCurrentShufflingStartShard(ShardNumber.of(data.getCurrentShufflingStartShard())); - state.setPreviousShufflingEpoch( - EpochNumber.castFrom(UInt64.valueOf(data.getPreviousShufflingEpoch()))); - state.setCurrentShufflingEpoch( - EpochNumber.castFrom(UInt64.valueOf(data.getCurrentShufflingEpoch()))); - state.setPreviousShufflingSeed(Hash32.fromHexString(data.getPreviousShufflingSeed())); - state.setCurrentShufflingSeed(Hash32.fromHexString(data.getCurrentShufflingSeed())); state.setPreviousJustifiedEpoch( EpochNumber.castFrom(UInt64.valueOf(data.getPreviousJustifiedEpoch()))); state.setCurrentJustifiedEpoch( @@ -240,7 +205,7 @@ public static MutableBeaconState parseBeaconState(SpecConstants specConstants, B state.setDepositIndex(UInt64.valueOf(data.getDepositIndex())); state.getValidatorRegistry().addAll(parseValidatorRegistry(data.getValidatorRegistry())); - state.getValidatorBalances().addAll(parseBalances(data.getValidatorBalances())); + state.getBalances().addAll(parseBalances(data.getValidatorBalances())); state.getLatestRandaoMixes().setAll(parseHashes(data.getLatestRandaoMixes())); state.getPreviousEpochAttestations().addAll( parsePendingAttestations(data.getPreviousEpochAttestations())); @@ -281,16 +246,19 @@ public static ValidatorRecord parseValidatorRecord(ValidatorData data) { return new ValidatorRecord( BLSPubkey.fromHexString(data.getPubkey()), Hash32.fromHexString(data.getWithdrawalCredentials()), + EpochNumber.castFrom(UInt64.valueOf(data.getActivationEligibilityEpoch())), EpochNumber.castFrom(UInt64.valueOf(data.getActivationEpoch())), EpochNumber.castFrom(UInt64.valueOf(data.getExitEpoch())), EpochNumber.castFrom(UInt64.valueOf(data.getWithdrawableEpoch())), - data.getInitiatedExit(), - data.getSlashed()); + data.getSlashed(), + Gwei.castFrom(UInt64.valueOf(data.getEffectiveBalance()))); } public static Eth1Data parseEth1Data(Eth1 data) { return new Eth1Data( - Hash32.fromHexString(data.getDepositRoot()), Hash32.fromHexString(data.getBlockHash())); + Hash32.fromHexString(data.getDepositRoot()), + UInt64.valueOf(data.getDepositCount()), + Hash32.fromHexString(data.getBlockHash())); } public static BeaconBlockHeader parseBeaconBlockHeader(BlockHeaderData data) { @@ -314,6 +282,7 @@ public static Fork parseFork(BeaconStateData.Fork data) { public static Crosslink parseCrosslink(CrossLinkData data) { return new Crosslink( EpochNumber.castFrom(UInt64.valueOf(data.getEpoch())), + Hash32.fromHexString(data.getPreviousCrosslinkRoot()), Hash32.fromHexString(data.getCrosslinkDataRoot())); } @@ -322,21 +291,19 @@ public static PendingAttestation parsePendingAttestation( return new PendingAttestation( Bitfield.of(BytesValue.fromHexString(attestationData.getAggregationBitfield())), parseAttestationData(attestationData.getData()), - Bitfield.of(BytesValue.fromHexString(attestationData.getCustodyBitfield())), - SlotNumber.castFrom(UInt64.valueOf(attestationData.getInclusionSlot()))); + SlotNumber.castFrom(UInt64.valueOf(attestationData.getInclusionSlot())), + ValidatorIndex.of(attestationData.getProposerIndex())); } public static AttestationData parseAttestationData(AttestationDataContainer data) { return new AttestationData( - SlotNumber.castFrom(UInt64.valueOf(data.getSlot())), Hash32.fromHexString(data.getBeaconBlockRoot()), EpochNumber.castFrom(UInt64.valueOf(data.getSourceEpoch())), Hash32.fromHexString(data.getSourceRoot()), + EpochNumber.castFrom(UInt64.valueOf(data.getSourceEpoch())), Hash32.fromHexString(data.getTargetRoot()), ShardNumber.of(data.getShard()), - new Crosslink( - EpochNumber.castFrom(UInt64.valueOf(data.getPreviousCrosslink().getEpoch())), - Hash32.fromHexString(data.getPreviousCrosslink().getCrosslinkDataRoot())), + Hash32.fromHexString(data.getPreviousCrosslinkRoot()), Hash32.fromHexString(data.getCrosslinkDataRoot())); } } diff --git a/test/src/test/java/org/ethereum/beacon/test/StateTests.java b/test/src/test/java/org/ethereum/beacon/test/StateTests.java index bcecaac63..61b48b428 100644 --- a/test/src/test/java/org/ethereum/beacon/test/StateTests.java +++ b/test/src/test/java/org/ethereum/beacon/test/StateTests.java @@ -13,7 +13,7 @@ public class StateTests extends TestUtils { public StateTests() {} @Test - @Ignore("signed_root and hash_tree_root results do not match") + @Ignore("signing_root and hash_tree_root results do not match") public void testState() { Path stateTestsPath = Paths.get(PATH_TO_TESTS, TESTS_DIR); runTestsInResourceDir( diff --git a/test/src/test/java/org/ethereum/beacon/test/runner/hash/TreeHashBasicRunner.java b/test/src/test/java/org/ethereum/beacon/test/runner/hash/TreeHashBasicRunner.java index 8c568e987..335fa724c 100644 --- a/test/src/test/java/org/ethereum/beacon/test/runner/hash/TreeHashBasicRunner.java +++ b/test/src/test/java/org/ethereum/beacon/test/runner/hash/TreeHashBasicRunner.java @@ -33,7 +33,7 @@ public TreeHashBasicRunner(TestCase testCase, BeaconChainSpec spec) { "TestCase runner accepts only TreeHashBasicTestCase.class as input!"); } this.testCase = (TreeHashBasicTestCase) testCase; - Function hashFunction = Hashes::keccak256; + Function hashFunction = Hashes::sha256; SSZHasher sszHasher = new SSZBuilder().withExternalVarResolver(new SpecConstantsResolver(spec.getConstants())) .withIncrementalHasher(true) diff --git a/test/src/test/java/org/ethereum/beacon/test/runner/hash/TreeHashContainerRunner.java b/test/src/test/java/org/ethereum/beacon/test/runner/hash/TreeHashContainerRunner.java index c9f108115..7f948ae76 100644 --- a/test/src/test/java/org/ethereum/beacon/test/runner/hash/TreeHashContainerRunner.java +++ b/test/src/test/java/org/ethereum/beacon/test/runner/hash/TreeHashContainerRunner.java @@ -47,7 +47,7 @@ public TreeHashContainerRunner(TestCase testCase, BeaconChainSpec spec) { "TestCase runner accepts only TreeHashContainerTestCase.class as input!"); } this.testCase = (TreeHashContainerTestCase) testCase; - Function hashFunction = Hashes::keccak256; + Function hashFunction = Hashes::sha256; SSZHasher sszHasher = new SSZBuilder().withExternalVarResolver(new SpecConstantsResolver(spec.getConstants())) .withIncrementalHasher(true) diff --git a/test/src/test/java/org/ethereum/beacon/test/runner/hash/TreeHashListRunner.java b/test/src/test/java/org/ethereum/beacon/test/runner/hash/TreeHashListRunner.java index 3bd1ae0b5..d48390b6d 100644 --- a/test/src/test/java/org/ethereum/beacon/test/runner/hash/TreeHashListRunner.java +++ b/test/src/test/java/org/ethereum/beacon/test/runner/hash/TreeHashListRunner.java @@ -41,7 +41,7 @@ public TreeHashListRunner(TestCase testCase, BeaconChainSpec spec) { "TestCase runner accepts only TreeHashListTestCase.class as input!"); } this.testCase = (TreeHashListTestCase) testCase; - Function hashFunction = Hashes::keccak256; + Function hashFunction = Hashes::sha256; SSZHasher sszHasher = new SSZBuilder().withExternalVarResolver(new SpecConstantsResolver(spec.getConstants())) .withIncrementalHasher(true) diff --git a/test/src/test/java/org/ethereum/beacon/test/runner/hash/TreeHashVectorRunner.java b/test/src/test/java/org/ethereum/beacon/test/runner/hash/TreeHashVectorRunner.java index 434d58f2c..14cba1d8a 100644 --- a/test/src/test/java/org/ethereum/beacon/test/runner/hash/TreeHashVectorRunner.java +++ b/test/src/test/java/org/ethereum/beacon/test/runner/hash/TreeHashVectorRunner.java @@ -43,7 +43,7 @@ public TreeHashVectorRunner(TestCase testCase, BeaconChainSpec spec) { "TestCase runner accepts only TreeHashListTestCase.class as input!"); } this.testCase = (TreeHashListTestCase) testCase; - Function hashFunction = Hashes::keccak256; + Function hashFunction = Hashes::sha256; SSZHasher sszHasher = new SSZBuilder().withExternalVarResolver(new SpecConstantsResolver(spec.getConstants())) .withIncrementalHasher(true) diff --git a/test/src/test/java/org/ethereum/beacon/test/runner/shuffle/ShuffleRunner.java b/test/src/test/java/org/ethereum/beacon/test/runner/shuffle/ShuffleRunner.java index ec2e29d00..c7a9ef00d 100644 --- a/test/src/test/java/org/ethereum/beacon/test/runner/shuffle/ShuffleRunner.java +++ b/test/src/test/java/org/ethereum/beacon/test/runner/shuffle/ShuffleRunner.java @@ -4,6 +4,7 @@ import org.ethereum.beacon.core.state.ValidatorRecord; import org.ethereum.beacon.core.types.BLSPubkey; import org.ethereum.beacon.core.types.EpochNumber; +import org.ethereum.beacon.core.types.Gwei; import org.ethereum.beacon.core.types.ValidatorIndex; import org.ethereum.beacon.test.runner.Runner; import org.ethereum.beacon.test.type.shuffle.ShuffleTestCase; @@ -54,12 +55,13 @@ public Optional run() { new ValidatorRecord( BLSPubkey.ZERO, Hash32.ZERO, + spec.getConstants().getFarFutureEpoch(), EpochNumber.castFrom(UInt64.valueOf(testValidator.getActivation_epoch())), EpochNumber.castFrom(UInt64.valueOf(testValidator.getExit_epoch())), EpochNumber.castFrom(UInt64.valueOf(testValidator.getActivation_epoch())) .plus(spec.getConstants().getMinValidatorWithdrawabilityDelay()), - false, // XXX: not used - false); + false, + spec.getConstants().getMaxEffectiveBalance()); validators.add(validatorRecord); } diff --git a/test/src/test/java/org/ethereum/beacon/test/runner/state/StateComparator.java b/test/src/test/java/org/ethereum/beacon/test/runner/state/StateComparator.java index a193e75aa..87ed60b9f 100644 --- a/test/src/test/java/org/ethereum/beacon/test/runner/state/StateComparator.java +++ b/test/src/test/java/org/ethereum/beacon/test/runner/state/StateComparator.java @@ -53,26 +53,10 @@ public Optional compare() { "Current justified epoch doesn't match: ", this::compareCurrentJustifiedEpoch, error); runComparison( "Current justified root doesn't match: ", this::compareCurrentJustifiedRoot, error); - runComparison( - "Current shuffling epoch doesn't match: ", this::compareCurrentShufflingEpoch, error); - runComparison( - "Current shuffling seed doesn't match: ", this::compareCurrentShufflingSeed, error); - runComparison( - "Current shuffling start shard doesn't match: ", - this::compareCurrentShufflingStartShard, - error); runComparison( "Previous justified epoch doesn't match: ", this::comparePreviousJustifiedEpoch, error); runComparison( "Previous justified root doesn't match: ", this::comparePreviousJustifiedRoot, error); - runComparison( - "Previous shuffling epoch doesn't match: ", this::comparePreviousShufflingEpoch, error); - runComparison( - "Previous shuffling seed doesn't match: ", this::comparePreviousShufflingSeed, error); - runComparison( - "Previous shuffling start shard doesn't match: ", - this::comparePreviousShufflingStartShard, - error); runComparison("Deposit index doesn't match: ", this::compareDepositIndex, error); runComparison("Eth1 data votes doesn't match: ", this::compareEth1DataVotes, error); runComparison("Finalized epoch doesn't match: ", this::compareFinalizedEpoch, error); @@ -89,10 +73,6 @@ public Optional compare() { runComparison("Latest randao mixes do not match: ", this::compareLatestRandaoMixes, error); runComparison("Latest slashed balances do not match: ", this::compareSlashedBalances, error); runComparison("Latest state roots do not match: ", this::compareLatestStateRoots, error); - runComparison( - "Validator registry update epoch doesn't match: ", - this::compareValidatorRegistryUpdateEpoch, - error); return error.length() == 0 ? Optional.empty() : Optional.of(error.toString()); } @@ -135,7 +115,7 @@ private Optional compareValidatorBalances() { return assertLists( StateTestUtils.parseBalances(expected.getValidatorBalances()), - actual.getValidatorBalances().listCopy()); + actual.getBalances().listCopy()); } private Optional compareSlashedBalances() { @@ -252,35 +232,6 @@ private Optional compareGenesisTime() { return assertEquals(expected.getGenesisTime(), actual.getGenesisTime().getValue()); } - private Optional compareCurrentShufflingEpoch() { - if (expected.getCurrentShufflingEpoch() == null) { - return Optional.empty(); - } - - return assertEquals( - EpochNumber.castFrom(UInt64.valueOf(expected.getCurrentShufflingEpoch())), - actual.getCurrentShufflingEpoch()); - } - - private Optional compareCurrentShufflingSeed() { - if (expected.getCurrentShufflingSeed() == null) { - return Optional.empty(); - } - - return assertEquals( - Hash32.fromHexString(expected.getCurrentShufflingSeed()), actual.getCurrentShufflingSeed()); - } - - private Optional compareCurrentShufflingStartShard() { - if (expected.getCurrentShufflingStartShard() == null) { - return Optional.empty(); - } - - return assertEquals( - expected.getCurrentShufflingStartShard(), - actual.getCurrentShufflingStartShard().getValue()); - } - private Optional comparePreviousJustifiedEpoch() { if (expected.getPreviousJustifiedEpoch() == null) { return Optional.empty(); @@ -301,46 +252,6 @@ private Optional comparePreviousJustifiedRoot() { actual.getPreviousJustifiedRoot()); } - private Optional comparePreviousShufflingEpoch() { - if (expected.getPreviousShufflingEpoch() == null) { - return Optional.empty(); - } - - return assertEquals( - EpochNumber.castFrom(UInt64.valueOf(expected.getPreviousShufflingEpoch())), - actual.getPreviousShufflingEpoch()); - } - - private Optional compareValidatorRegistryUpdateEpoch() { - if (expected.getValidatorRegistryUpdateEpoch() == null) { - return Optional.empty(); - } - - return assertEquals( - EpochNumber.castFrom(UInt64.valueOf(expected.getValidatorRegistryUpdateEpoch())), - actual.getValidatorRegistryUpdateEpoch()); - } - - private Optional comparePreviousShufflingSeed() { - if (expected.getPreviousShufflingSeed() == null) { - return Optional.empty(); - } - - return assertEquals( - Hash32.fromHexString(expected.getPreviousShufflingSeed()), - actual.getPreviousShufflingSeed()); - } - - private Optional comparePreviousShufflingStartShard() { - if (expected.getPreviousShufflingStartShard() == null) { - return Optional.empty(); - } - - return assertEquals( - expected.getPreviousShufflingStartShard(), - actual.getPreviousShufflingStartShard().getValue()); - } - private Optional compareDepositIndex() { if (expected.getDepositIndex() == null) { return Optional.empty(); diff --git a/test/src/test/java/org/ethereum/beacon/test/type/state/StateTestCase.java b/test/src/test/java/org/ethereum/beacon/test/type/state/StateTestCase.java index 5bbb62fe4..3c96ee01c 100644 --- a/test/src/test/java/org/ethereum/beacon/test/type/state/StateTestCase.java +++ b/test/src/test/java/org/ethereum/beacon/test/type/state/StateTestCase.java @@ -476,17 +476,20 @@ public static class ValidatorData { @JsonProperty("activation_epoch") private String activationEpoch; + @JsonProperty("activation_eligibility_epoch") + private String activationEligibilityEpoch; + @JsonProperty("exit_epoch") private String exitEpoch; @JsonProperty("withdrawable_epoch") private String withdrawableEpoch; - @JsonProperty("initiated_exit") - private Boolean initiatedExit; - private Boolean slashed; + @JsonProperty("effective_balance") + private String effectiveBalance; + public String getPubkey() { return pubkey; } @@ -511,6 +514,14 @@ public void setActivationEpoch(String activationEpoch) { this.activationEpoch = activationEpoch; } + public String getActivationEligibilityEpoch() { + return activationEligibilityEpoch; + } + + public void setActivationEligibilityEpoch(String activationEligibilityEpoch) { + this.activationEligibilityEpoch = activationEligibilityEpoch; + } + public String getExitEpoch() { return exitEpoch; } @@ -527,14 +538,6 @@ public void setWithdrawableEpoch(String withdrawableEpoch) { this.withdrawableEpoch = withdrawableEpoch; } - public Boolean getInitiatedExit() { - return initiatedExit; - } - - public void setInitiatedExit(Boolean initiatedExit) { - this.initiatedExit = initiatedExit; - } - public Boolean getSlashed() { return slashed; } @@ -542,6 +545,14 @@ public Boolean getSlashed() { public void setSlashed(Boolean slashed) { this.slashed = slashed; } + + public String getEffectiveBalance() { + return effectiveBalance; + } + + public void setEffectiveBalance(String effectiveBalance) { + this.effectiveBalance = effectiveBalance; + } } @JsonIgnoreProperties(ignoreUnknown = true) @@ -560,6 +571,9 @@ public static class AttestationData { @JsonProperty("inclusion_slot") private String inclusionSlot; + @JsonProperty("proposer_index") + private Long proposerIndex; + public String getInclusionSlot() { return inclusionSlot; } @@ -600,6 +614,14 @@ public void setAggregateSignature(String aggregateSignature) { this.aggregateSignature = aggregateSignature; } + public Long getProposerIndex() { + return proposerIndex; + } + + public void setProposerIndex(Long proposerIndex) { + this.proposerIndex = proposerIndex; + } + public static class AttestationDataContainer { private String slot; @@ -617,8 +639,8 @@ public static class AttestationDataContainer { private Long shard; - @JsonProperty("previous_crosslink") - private CrossLinkData previousCrosslink; + @JsonProperty("previous_crosslink_root") + private String previousCrosslinkRoot; @JsonProperty("crosslink_data_root") private String crosslinkDataRoot; @@ -671,12 +693,12 @@ public void setShard(Long shard) { this.shard = shard; } - public CrossLinkData getPreviousCrosslink() { - return previousCrosslink; + public String getPreviousCrosslinkRoot() { + return previousCrosslinkRoot; } - public void setPreviousCrosslink(CrossLinkData previousCrosslink) { - this.previousCrosslink = previousCrosslink; + public void setPreviousCrosslinkRoot(String previousCrosslinkRoot) { + this.previousCrosslinkRoot = previousCrosslinkRoot; } public String getCrosslinkDataRoot() { @@ -692,6 +714,9 @@ public void setCrosslinkDataRoot(String crosslinkDataRoot) { public static class CrossLinkData { private String epoch; + @JsonProperty("previous_crosslink_root") + private String previousCrosslinkRoot; + @JsonProperty("crosslink_data_root") private String crosslinkDataRoot; @@ -703,6 +728,14 @@ public void setEpoch(String epoch) { this.epoch = epoch; } + public String getPreviousCrosslinkRoot() { + return previousCrosslinkRoot; + } + + public void setPreviousCrosslinkRoot(String previousCrosslinkRoot) { + this.previousCrosslinkRoot = previousCrosslinkRoot; + } + public String getCrosslinkDataRoot() { return crosslinkDataRoot; } @@ -911,6 +944,9 @@ public static class Eth1 { @JsonProperty("deposit_root") private String depositRoot; + @JsonProperty("deposit_count") + private String depositCount; + @JsonProperty("block_hash") private String blockHash; @@ -922,6 +958,14 @@ public void setDepositRoot(String depositRoot) { this.depositRoot = depositRoot; } + public String getDepositCount() { + return depositCount; + } + + public void setDepositCount(String depositCount) { + this.depositCount = depositCount; + } + public String getBlockHash() { return blockHash; } @@ -967,45 +1011,53 @@ public void setHeader2(BeaconStateData.BlockHeaderData header2) { } public static class SlashableAttestationData { - @JsonProperty("validator_indices") - private List validatorIndices; + @JsonProperty("custody_bit_0_indices") + private List custodyBit0Indices; + @JsonProperty("custody_bit_1_indices") + private List custodyBit1Indices; @JsonProperty("data") private AttestationDataContainer data; - @JsonProperty("custody_bitfield") - private String custodyBitfield; - @JsonProperty("aggregate_signature") - private String aggregateSignature; + @JsonProperty("signature") + private String signature; - public List getValidatorIndices() { - return validatorIndices; + public String getSignature() { + return signature; } - public void setValidatorIndices(List validatorIndices) { - this.validatorIndices = validatorIndices; + public void setSignature(String signature) { + this.signature = signature; } - public AttestationDataContainer getData() { - return data; + public List getCustodyBit0Indices() { + return custodyBit0Indices; } - public void setData(AttestationDataContainer data) { - this.data = data; + public void setCustodyBit0Indices(List custodyBit0Indices) { + this.custodyBit0Indices = custodyBit0Indices; + } + + public List getCustodyBit1Indices() { + return custodyBit1Indices; + } + + public void setCustodyBit1Indices(List custodyBit1Indices) { + this.custodyBit1Indices = custodyBit1Indices; } - public String getCustodyBitfield() { - return custodyBitfield; + public AttestationDataContainer getData() { + return data; } - public void setCustodyBitfield(String custodyBitfield) { - this.custodyBitfield = custodyBitfield; + public void setData(AttestationDataContainer data) { + this.data = data; } public String getAggregateSignature() { - return aggregateSignature; + return signature; } public void setAggregateSignature(String aggregateSignature) { - this.aggregateSignature = aggregateSignature; + this.signature = aggregateSignature; } } @@ -1066,11 +1118,11 @@ public void setDepositData(DepositDataContainer depositData) { } public static class DepositDataContainer { + private String pubkey; + @JsonProperty("withdrawal_credentials") + private String withdrawalCredentials; private String amount; - private Long timestamp; - - @JsonProperty("deposit_input") - private DepositInputData depositInput; + private String signature; public String getAmount() { return amount; @@ -1080,54 +1132,28 @@ public void setAmount(String amount) { this.amount = amount; } - public Long getTimestamp() { - return timestamp; + public String getPubkey() { + return pubkey; } - public void setTimestamp(Long timestamp) { - this.timestamp = timestamp; + public void setPubkey(String pubkey) { + this.pubkey = pubkey; } - public DepositInputData getDepositInput() { - return depositInput; + public String getWithdrawalCredentials() { + return withdrawalCredentials; } - public void setDepositInput(DepositInputData depositInput) { - this.depositInput = depositInput; + public void setWithdrawalCredentials(String withdrawalCredentials) { + this.withdrawalCredentials = withdrawalCredentials; } - public static class DepositInputData { - private String pubkey; - - @JsonProperty("withdrawal_credentials") - private String withdrawalCredentials; - - @JsonProperty("proof_of_possession") - private String proofOfPossession; - - public String getPubkey() { - return pubkey; - } - - public void setPubkey(String pubkey) { - this.pubkey = pubkey; - } - - public String getWithdrawalCredentials() { - return withdrawalCredentials; - } - - public void setWithdrawalCredentials(String withdrawalCredentials) { - this.withdrawalCredentials = withdrawalCredentials; - } - - public String getProofOfPossession() { - return proofOfPossession; - } + public String getSignature() { + return signature; + } - public void setProofOfPossession(String proofOfPossession) { - this.proofOfPossession = proofOfPossession; - } + public void setSignature(String signature) { + this.signature = signature; } } } diff --git a/types/src/main/java/tech/pegasys/artemis/util/collections/ReadVector.java b/types/src/main/java/tech/pegasys/artemis/util/collections/ReadVector.java index 22ecbb84e..defac0505 100644 --- a/types/src/main/java/tech/pegasys/artemis/util/collections/ReadVector.java +++ b/types/src/main/java/tech/pegasys/artemis/util/collections/ReadVector.java @@ -1,6 +1,21 @@ package tech.pegasys.artemis.util.collections; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; + public interface ReadVector extends ReadList { + /** Wraps with creating of new vector */ + static ReadVector wrap( + List srcList, Function indexConverter) { + return ListImpl.wrap(new ArrayList<>(srcList), indexConverter); + } + + default ReadVector vectorCopy() { + ReadVector res = createMutableCopy(); + return res; + } + } diff --git a/types/src/main/java/tech/pegasys/artemis/util/uint/UInt64s.java b/types/src/main/java/tech/pegasys/artemis/util/uint/UInt64s.java index 29c4d02ac..46843e9b7 100644 --- a/types/src/main/java/tech/pegasys/artemis/util/uint/UInt64s.java +++ b/types/src/main/java/tech/pegasys/artemis/util/uint/UInt64s.java @@ -13,6 +13,11 @@ package tech.pegasys.artemis.util.uint; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + public class UInt64s { public static C max(C v1, C v2) { @@ -22,4 +27,36 @@ public static C max(C v1, C v2) { public static C min(C v1, C v2) { return v1.compareTo(v2) < 0 ? v1 : v2; } + + public static Stream range(UInt64 fromInclusive, UInt64 toExclusive) { + return StreamSupport.stream(iterate(fromInclusive, toExclusive).spliterator(), false); + } + + public static Iterable iterate(UInt64 fromInclusive, UInt64 toExclusive) { + class Iter implements Iterator { + private UInt64 cur; + private UInt64 end; + private boolean increasing; + + private Iter(UInt64 from, UInt64 to, boolean increasing) { + this.increasing = increasing; + this.cur = from; + this.end = to; + } + + @Override + public boolean hasNext() { + return increasing ? cur.compareTo(end) < 0 : cur.compareTo(end) > 0; + } + + @Override + public UInt64 next() { + if (!hasNext()) throw new NoSuchElementException(); + UInt64 ret = cur; + cur = increasing ? cur.increment() : cur.decrement(); + return ret; + } + } + return () -> new Iter(fromInclusive, toExclusive, true); + } } diff --git a/validator/src/main/java/org/ethereum/beacon/validator/BeaconChainProposer.java b/validator/src/main/java/org/ethereum/beacon/validator/BeaconChainProposer.java index aa24a89f2..65eab0ece 100644 --- a/validator/src/main/java/org/ethereum/beacon/validator/BeaconChainProposer.java +++ b/validator/src/main/java/org/ethereum/beacon/validator/BeaconChainProposer.java @@ -2,8 +2,10 @@ import org.ethereum.beacon.chain.observer.ObservableBeaconState; import org.ethereum.beacon.core.BeaconBlock; +import org.ethereum.beacon.core.BeaconState; import org.ethereum.beacon.core.types.BLSSignature; import org.ethereum.beacon.validator.crypto.MessageSigner; +import tech.pegasys.artemis.util.bytes.Bytes32; /** * An interface of beacon chain proposer. A part of beacon validator logic. @@ -22,4 +24,14 @@ public interface BeaconChainProposer { * @return created block. */ BeaconBlock propose(ObservableBeaconState observableState, MessageSigner signer); + + /** + * Given a state returns graffiti value. + * + * @param state a state. + * @return graffiti value. + */ + default Bytes32 getGraffiti(BeaconState state) { + return Bytes32.ZERO; + } } diff --git a/validator/src/main/java/org/ethereum/beacon/validator/MultiValidatorService.java b/validator/src/main/java/org/ethereum/beacon/validator/MultiValidatorService.java index 51a5d9296..8d6144040 100644 --- a/validator/src/main/java/org/ethereum/beacon/validator/MultiValidatorService.java +++ b/validator/src/main/java/org/ethereum/beacon/validator/MultiValidatorService.java @@ -6,7 +6,6 @@ import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; @@ -24,6 +23,7 @@ import org.ethereum.beacon.core.spec.SpecConstants; import org.ethereum.beacon.core.state.ShardCommittee; import org.ethereum.beacon.core.types.BLSPubkey; +import org.ethereum.beacon.core.types.ShardNumber; import org.ethereum.beacon.core.types.SlotNumber; import org.ethereum.beacon.core.types.Time; import org.ethereum.beacon.core.types.ValidatorIndex; @@ -135,7 +135,7 @@ private void initFromLatestBeaconState(BeaconState state) { /** * Keeps the most recent state in memory. * - *

Recent state is required by delayed tasks like {@link #attest(ValidatorIndex)}. + *

Recent state is required by delayed tasks like {@link #attest(ValidatorIndex, ShardNumber)}. * * @param state state came from the outside. */ @@ -189,8 +189,8 @@ private void processState(ObservableBeaconState observableState) { *

    *
  • {@link #propose(ValidatorIndex, ObservableBeaconState)} routine is triggered instantly * with received {@code observableState} object. - *
  • {@link #attest(ValidatorIndex)} routine is a delayed task, it's called with {@link - * #recentState} object. + *
  • {@link #attest(ValidatorIndex, ShardNumber)} routine is a delayed task, it's called with + * {@link #recentState} object. *
* * @param observableState a state that validator tasks are executed with. @@ -200,7 +200,7 @@ void runTasks(final ObservableBeaconState observableState) { BeaconStateEx state = observableState.getLatestSlotState(); // trigger proposer - ValidatorIndex proposerIndex = spec.get_beacon_proposer_index(state, state.getSlot()); + ValidatorIndex proposerIndex = spec.get_beacon_proposer_index(state); if (initialized.containsKey(proposerIndex) && state.getTransition() == TransitionType.SLOT && !isGenesis(state)) { runAsync(() -> propose(proposerIndex, observableState)); @@ -208,12 +208,13 @@ void runTasks(final ObservableBeaconState observableState) { // trigger attester at a halfway through the slot Time startAt = spec.get_slot_middle_time(state, state.getSlot()); - List committees = + List slotCommittees = spec.get_crosslink_committees_at_slot(state, state.getSlot()); - for (ShardCommittee sc : committees) { - sc.getCommittee().stream() + for (ShardCommittee shardCommittee : slotCommittees) { + ShardNumber shard = shardCommittee.getShard(); + shardCommittee.getCommittee().stream() .filter(initialized::containsKey) - .forEach(index -> schedule(startAt, () -> this.attest(index))); + .forEach(index -> schedule(startAt, () -> this.attest(index, shard))); } } @@ -259,7 +260,7 @@ private void propose(ValidatorIndex index, final ObservableBeaconState observabl newBlock.toString( spec.getConstants(), observableState.getLatestSlotState().getGenesisTime(), - spec::signed_root), + spec::signing_root), String.format("%.3f", (double) total / 1_000_000_000d)); } } @@ -272,17 +273,16 @@ private void propose(ValidatorIndex index, final ObservableBeaconState observabl * #recentState}. * * @param index index of attester. + * @param shard number of crosslinking shard. */ - private void attest(ValidatorIndex index) { + private void attest(ValidatorIndex index, ShardNumber shard) { final ObservableBeaconState observableState = this.recentState; final BeaconState state = observableState.getLatestSlotState(); - Optional validatorCommittee = getValidatorCommittee(index, state); BLS381Credentials credentials = initialized.get(index); - if (validatorCommittee.isPresent() && credentials != null) { + if (credentials != null) { Attestation attestation = - attester.attest( - index, validatorCommittee.get().getShard(), observableState, credentials.getSigner()); + attester.attest(index, shard, observableState, credentials.getSigner()); propagateAttestation(attestation); logger.info( @@ -293,7 +293,7 @@ private void attest(ValidatorIndex index) { .toString( spec.getConstants(), observableState.getLatestSlotState().getGenesisTime(), - spec::signed_root), + spec::signing_root), state.getSlot()); } } @@ -309,13 +309,6 @@ private void setSlotProcessed(BeaconState state) { this.lastProcessedSlot = state.getSlot(); } - /** Returns committee where the validator participates if any */ - private Optional getValidatorCommittee(ValidatorIndex index, BeaconState state) { - List committees = - spec.get_crosslink_committees_at_slot(state, state.getSlot()); - return committees.stream().filter(sc -> sc.getCommittee().contains(index)).findFirst(); - } - /** * Checks whether slot of the state was already processed. * diff --git a/validator/src/main/java/org/ethereum/beacon/validator/attester/BeaconChainAttesterImpl.java b/validator/src/main/java/org/ethereum/beacon/validator/attester/BeaconChainAttesterImpl.java index 4d5147d98..1d8d6b81e 100644 --- a/validator/src/main/java/org/ethereum/beacon/validator/attester/BeaconChainAttesterImpl.java +++ b/validator/src/main/java/org/ethereum/beacon/validator/attester/BeaconChainAttesterImpl.java @@ -3,7 +3,6 @@ import static org.ethereum.beacon.core.spec.SignatureDomains.ATTESTATION; import com.google.common.annotations.VisibleForTesting; -import java.util.Collections; import java.util.List; import org.ethereum.beacon.chain.observer.ObservableBeaconState; import org.ethereum.beacon.consensus.BeaconChainSpec; @@ -12,7 +11,6 @@ import org.ethereum.beacon.core.operations.Attestation; import org.ethereum.beacon.core.operations.attestation.AttestationData; import org.ethereum.beacon.core.operations.attestation.AttestationDataAndCustodyBit; -import org.ethereum.beacon.core.operations.attestation.Crosslink; import org.ethereum.beacon.core.types.BLSSignature; import org.ethereum.beacon.core.types.Bitfield; import org.ethereum.beacon.core.types.EpochNumber; @@ -50,22 +48,22 @@ public Attestation attest( MessageSigner signer) { BeaconState state = observableState.getLatestSlotState(); - SlotNumber slot = state.getSlot(); - Hash32 beaconBlockRoot = spec.signed_root(observableState.getHead()); + Hash32 beaconBlockRoot = spec.signing_root(observableState.getHead()); + EpochNumber targetEpoch = spec.slot_to_epoch(state.getSlot()); Hash32 targetRoot = getTargetRoot(state, observableState.getHead()); Hash32 crosslinkDataRoot = Hash32.ZERO; // Note: This is a stub for phase 0. - Crosslink previousCrosslink = getPreviousCrosslink(state, shard); + Hash32 previousCrosslinkRoot = getPreviousCrosslinkRoot(state, shard); EpochNumber sourceEpoch = state.getCurrentJustifiedEpoch(); Hash32 sourceRoot = getSourceRoot(state, observableState.getHead()); AttestationData data = new AttestationData( - slot, beaconBlockRoot, sourceEpoch, sourceRoot, + targetEpoch, targetRoot, shard, - previousCrosslink, + previousCrosslinkRoot, crosslinkDataRoot); List committee = getCommittee(state, shard); @@ -86,29 +84,21 @@ public Attestation attest( */ @VisibleForTesting List getCommittee(BeaconState state, ShardNumber shard) { - if (shard.equals(spec.getConstants().getBeaconChainShardNumber())) { - return spec.get_crosslink_committees_at_slot(state, state.getSlot()).get(0).getCommittee(); - } else { - return spec - .get_crosslink_committees_at_slot(state, state.getSlot()).stream() - .filter(sc -> sc.getShard().equals(shard)) - .findFirst() - .map(sc -> sc.getCommittee()) - .orElse(Collections.emptyList()); - } + EpochNumber epoch = spec.get_current_epoch(state); + return spec.get_crosslink_committee(state, epoch, shard); } /* Note: This can be looked up in the state using - get_block_root(state, head.slot - head.slot % SLOTS_PER_EPOCH). + get_block_root_at_slot(state, head.slot - head.slot % SLOTS_PER_EPOCH). */ @VisibleForTesting Hash32 getTargetRoot(BeaconState state, BeaconBlock head) { SlotNumber epochBoundarySlot = spec.get_epoch_start_slot(spec.slot_to_epoch(head.getSlot())); if (epochBoundarySlot.equals(head.getSlot())) { - return spec.signed_root(head); + return spec.signing_root(head); } else { - return spec.get_block_root(state, epochBoundarySlot); + return spec.get_block_root_at_slot(state, epochBoundarySlot); } } @@ -117,15 +107,15 @@ Hash32 getTargetRoot(BeaconState state, BeaconBlock head) { where state is the beacon state at head and shard is the validator's assigned shard. */ @VisibleForTesting - Crosslink getPreviousCrosslink(BeaconState state, ShardNumber shard) { - return state.getCurrentCrosslinks().get(shard); + Hash32 getPreviousCrosslinkRoot(BeaconState state, ShardNumber shard) { + return spec.hash_tree_root(state.getCurrentCrosslinks().get(shard)); } /* Set attestation_data.justified_block_root = hash_tree_root(justified_block) where justified_block is the block at state.justified_slot in the chain defined by head. - Note: This can be looked up in the state using get_block_root(state, justified_slot). + Note: This can be looked up in the state using get_block_root_at_slot(state, justified_slot). */ @VisibleForTesting Hash32 getSourceRoot(BeaconState state, BeaconBlock head) { @@ -172,8 +162,7 @@ private BLSSignature getAggregateSignature( AttestationDataAndCustodyBit attestationDataAndCustodyBit = new AttestationDataAndCustodyBit(data, false); Hash32 hash = spec.hash_tree_root(attestationDataAndCustodyBit); - UInt64 domain = spec.get_domain(state.getFork(), - spec.get_current_epoch(state), ATTESTATION); + UInt64 domain = spec.get_domain(state, ATTESTATION); return signer.sign(hash, domain); } } diff --git a/validator/src/main/java/org/ethereum/beacon/validator/proposer/BeaconChainProposerImpl.java b/validator/src/main/java/org/ethereum/beacon/validator/proposer/BeaconChainProposerImpl.java index 2ac20de96..d5ef549db 100644 --- a/validator/src/main/java/org/ethereum/beacon/validator/proposer/BeaconChainProposerImpl.java +++ b/validator/src/main/java/org/ethereum/beacon/validator/proposer/BeaconChainProposerImpl.java @@ -1,17 +1,19 @@ package org.ethereum.beacon.validator.proposer; -import static org.ethereum.beacon.core.spec.SignatureDomains.BEACON_BLOCK; +import static org.ethereum.beacon.core.spec.SignatureDomains.BEACON_PROPOSER; import static org.ethereum.beacon.core.spec.SignatureDomains.RANDAO; +import java.util.Comparator; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; import org.ethereum.beacon.chain.observer.ObservableBeaconState; import org.ethereum.beacon.chain.observer.PendingOperations; +import org.ethereum.beacon.consensus.BeaconChainSpec; import org.ethereum.beacon.consensus.BeaconStateEx; import org.ethereum.beacon.consensus.BlockTransition; -import org.ethereum.beacon.consensus.BeaconChainSpec; -import org.ethereum.beacon.consensus.StateTransition; import org.ethereum.beacon.core.BeaconBlock; import org.ethereum.beacon.core.BeaconBlock.Builder; import org.ethereum.beacon.core.BeaconBlockBody; @@ -23,7 +25,6 @@ import org.ethereum.beacon.core.operations.VoluntaryExit; import org.ethereum.beacon.core.operations.slashing.AttesterSlashing; import org.ethereum.beacon.core.state.Eth1Data; -import org.ethereum.beacon.core.state.Eth1DataVote; import org.ethereum.beacon.core.types.BLSSignature; import org.ethereum.beacon.pow.DepositContract; import org.ethereum.beacon.pow.DepositContract.DepositInfo; @@ -31,6 +32,7 @@ import org.ethereum.beacon.validator.ValidatorService; import org.ethereum.beacon.validator.crypto.MessageSigner; import tech.pegasys.artemis.ethereum.core.Hash32; +import tech.pegasys.artemis.util.bytes.Bytes32; import tech.pegasys.artemis.util.collections.ReadList; import tech.pegasys.artemis.util.uint.UInt64; @@ -49,16 +51,6 @@ public class BeaconChainProposerImpl implements BeaconChainProposer { /** Eth1 deposit contract. */ private DepositContract depositContract; - public BeaconChainProposerImpl( - BeaconChainSpec spec, - BlockTransition perBlockTransition, - StateTransition perEpochTransition, - DepositContract depositContract) { - this.spec = spec; - this.perBlockTransition = perBlockTransition; - this.depositContract = depositContract; - } - public BeaconChainProposerImpl( BeaconChainSpec spec, BlockTransition perBlockTransition, @@ -73,7 +65,7 @@ public BeaconBlock propose( ObservableBeaconState observableState, MessageSigner signer) { BeaconStateEx state = observableState.getLatestSlotState(); - Hash32 parentRoot = spec.get_block_root(state, state.getSlot().decrement()); + Hash32 parentRoot = spec.get_block_root_at_slot(state, state.getSlot().decrement()); BLSSignature randaoReveal = getRandaoReveal(state, signer); Eth1Data eth1Data = getEth1Data(state); BeaconBlockBody blockBody = @@ -85,7 +77,7 @@ public BeaconBlock propose( .withSlot(state.getSlot()) .withParentRoot(parentRoot) .withStateRoot(Hash32.ZERO) - .withSignature(spec.getConstants().getEmptySignature()) + .withSignature(BLSSignature.ZERO) .withBody(blockBody); // calculate state_root @@ -111,9 +103,8 @@ public BeaconBlock propose( */ private BLSSignature getProposalSignature( BeaconState state, BeaconBlock block, MessageSigner signer) { - Hash32 proposalRoot = spec.signed_root(block); - UInt64 domain = spec.get_domain(state.getFork(), - spec.get_current_epoch(state), BEACON_BLOCK); + Hash32 proposalRoot = spec.signing_root(block); + UInt64 domain = spec.get_domain(state, BEACON_PROPOSER); return signer.sign(proposalRoot, domain); } @@ -126,8 +117,7 @@ private BLSSignature getProposalSignature( */ private BLSSignature getRandaoReveal(BeaconState state, MessageSigner signer) { Hash32 hash = spec.hash_tree_root(spec.slot_to_epoch(state.getSlot())); - UInt64 domain = spec.get_domain(state.getFork(), - spec.get_current_epoch(state), RANDAO); + UInt64 domain = spec.get_domain(state, RANDAO); return signer.sign(hash, domain); } @@ -149,29 +139,23 @@ private BLSSignature getRandaoReveal(BeaconState state, MessageSigner eth1DataVotes = state.getEth1DataVotes(); + ReadList eth1DataVotes = state.getEth1DataVotes(); Optional contractData = depositContract.getLatestEth1Data(); - if (eth1DataVotes.isEmpty()) { - return contractData.orElse(state.getLatestEth1Data()); + Map votes = new HashMap<>(); + for (Eth1Data eth1Data : eth1DataVotes) { + votes.compute(eth1Data, (key, count) -> (count == null) ? 1 : count + 1); } - UInt64 maxVotes = - eth1DataVotes.stream().map(Eth1DataVote::getVoteCount).max(UInt64::compareTo).get(); - Eth1DataVote bestVote = - eth1DataVotes.stream() - .filter(eth1DataVote -> eth1DataVote.getVoteCount().equals(maxVotes)) - .reduce((first, second) -> second) - .get(); + Optional bestVote = votes.keySet().stream().max(Comparator.comparing(votes::get)); // verify best vote data and return if verification passed, - // otherwise, return data from contract - if (depositContract.hasDepositRoot( - bestVote.getEth1Data().getBlockHash(), bestVote.getEth1Data().getDepositRoot())) { - return bestVote.getEth1Data(); - } else { - return contractData.orElse(state.getLatestEth1Data()); - } + // otherwise, return data from the contract + return bestVote + .filter( + eth1Data -> + depositContract.hasDepositRoot(eth1Data.getBlockHash(), eth1Data.getDepositRoot())) + .orElse(contractData.orElse(state.getLatestEth1Data())); } /** @@ -194,8 +178,9 @@ private BeaconBlockBody getBlockBody( List attestations = operations.peekAggregatedAttestations( spec.getConstants().getMaxAttestations(), - state.getSlot().minus(spec.getConstants().getSlotsPerEpoch()), - state.getSlot().minus(spec.getConstants().getMinAttestationInclusionDelay())); + state, + state.getSlot().minusSat(spec.getConstants().getSlotsPerEpoch()), + state.getSlot().minusSat(spec.getConstants().getMinAttestationInclusionDelay())); List voluntaryExits = operations.peekExits(spec.getConstants().getMaxVoluntaryExits()); List transfers = operations.peekTransfers(spec.getConstants().getMaxTransfers()); @@ -210,10 +195,12 @@ private BeaconBlockBody getBlockBody( .stream() .map(DepositInfo::getDeposit) .collect(Collectors.toList()); + Bytes32 graffiti = getGraffiti(state); - return new BeaconBlockBody( + return BeaconBlockBody.create( randaoReveal, eth1Data, + graffiti, proposerSlashings, attesterSlashings, attestations, diff --git a/validator/src/test/java/org/ethereum/beacon/validator/MultiValidatorServiceTest.java b/validator/src/test/java/org/ethereum/beacon/validator/MultiValidatorServiceTest.java index 631d57303..95503eec2 100644 --- a/validator/src/test/java/org/ethereum/beacon/validator/MultiValidatorServiceTest.java +++ b/validator/src/test/java/org/ethereum/beacon/validator/MultiValidatorServiceTest.java @@ -9,11 +9,13 @@ import org.ethereum.beacon.chain.observer.ObservableBeaconState; import org.ethereum.beacon.chain.util.ObservableBeaconStateTestUtil; import org.ethereum.beacon.consensus.BeaconChainSpec; +import org.ethereum.beacon.core.BeaconState; import org.ethereum.beacon.core.spec.SpecConstants; import org.ethereum.beacon.core.state.ValidatorRecord; import org.ethereum.beacon.core.types.BLSPubkey; import org.ethereum.beacon.core.types.BLSSignature; import org.ethereum.beacon.core.types.EpochNumber; +import org.ethereum.beacon.core.types.Gwei; import org.ethereum.beacon.core.types.SlotNumber; import org.ethereum.beacon.core.types.ValidatorIndex; import org.ethereum.beacon.validator.crypto.BLS381Credentials; @@ -23,6 +25,7 @@ import org.junit.Assert; import org.junit.Test; import org.mockito.Mockito; +import org.mockito.stubbing.Stubber; import tech.pegasys.artemis.ethereum.core.Hash32; import tech.pegasys.artemis.util.bytes.Bytes48; import tech.pegasys.artemis.util.collections.ReadList; @@ -72,18 +75,26 @@ public void outboundRecentStateIsIgnored() { ObservableBeaconState currentSlotState = ObservableBeaconStateTestUtil.createInitialState(random, spec, currentSlot); - Mockito.doReturn(true) + Mockito.doReturn(false) .when(spec) - .is_current_slot(eq(currentSlotState.getLatestSlotState()), anyLong()); + .is_current_slot(any(), anyLong()); // state wasn't kept validator.onNewState(outdatedState); Assert.assertNull(validator.getRecentState()); + Mockito.doReturn(true) + .when(spec) + .is_current_slot(any(), anyLong()); + // state was kept validator.onNewState(currentSlotState); Assert.assertEquals(currentSlotState, validator.getRecentState()); + Mockito.doReturn(false) + .when(spec) + .is_current_slot(any(), anyLong()); + // state wasn't updated validator.onNewState(outdatedState); Assert.assertEquals(currentSlotState, validator.getRecentState()); @@ -101,12 +112,6 @@ public void initService() { ValidatorServiceTestUtil.mockBeaconChainValidator(random, spec, blsCredentials); ValidatorIndex validatorIndex = ValidatorIndex.of(Math.abs(random.nextInt()) % 10 + 10); - - ObservableBeaconState outdatedState = - ObservableBeaconStateTestUtil.createInitialState(random, spec, SlotNumber.ZERO); - validator.onNewState(outdatedState); - Assert.assertNull(validator.getRecentState()); - Mockito.verify(validator, Mockito.never()).runTasks(any()); SlotNumber currentSlot = SlotNumber.of(Math.abs(random.nextLong()) % 10 + 10); @@ -208,8 +213,9 @@ private ReadList createRegistry( EpochNumber.ZERO, EpochNumber.ZERO, EpochNumber.ZERO, + EpochNumber.ZERO, Boolean.FALSE, - Boolean.FALSE))); + Gwei.ZERO))); validatorRegistry.add( new ValidatorRecord( pubkey, @@ -217,8 +223,9 @@ private ReadList createRegistry( EpochNumber.ZERO, EpochNumber.ZERO, EpochNumber.ZERO, + EpochNumber.ZERO, Boolean.FALSE, - Boolean.FALSE)); + Gwei.ZERO)); return validatorRegistry; } diff --git a/validator/src/test/java/org/ethereum/beacon/validator/attester/BeaconChainAttesterTest.java b/validator/src/test/java/org/ethereum/beacon/validator/attester/BeaconChainAttesterTest.java index 7ee6694e0..805d48f56 100644 --- a/validator/src/test/java/org/ethereum/beacon/validator/attester/BeaconChainAttesterTest.java +++ b/validator/src/test/java/org/ethereum/beacon/validator/attester/BeaconChainAttesterTest.java @@ -13,8 +13,6 @@ import org.ethereum.beacon.core.operations.Attestation; import org.ethereum.beacon.core.operations.attestation.AttestationData; import org.ethereum.beacon.core.operations.attestation.AttestationDataAndCustodyBit; -import org.ethereum.beacon.core.operations.attestation.Crosslink; -import org.ethereum.beacon.core.spec.SpecConstants; import org.ethereum.beacon.core.spec.SignatureDomains; import org.ethereum.beacon.core.types.BLSSignature; import org.ethereum.beacon.core.types.ShardNumber; @@ -25,6 +23,7 @@ import org.junit.Test; import org.mockito.Mockito; import tech.pegasys.artemis.ethereum.core.Hash32; +import tech.pegasys.artemis.util.uint.UInt64; public class BeaconChainAttesterTest { @@ -45,11 +44,12 @@ public void attestASlot() { ValidatorIndex validatorIndex = committee.get(indexIntoCommittee); Hash32 targetRoot = Hash32.random(random); Hash32 sourceRoot = Hash32.random(random); - ShardNumber shard = spec.getConstants().getBeaconChainShardNumber(); + ShardNumber shard = ShardNumber.of( + UInt64.random(random).modulo(spec.getConstants().getShardCount())); Mockito.doReturn(committee).when(attester).getCommittee(any(), any()); Mockito.doReturn(targetRoot).when(attester).getTargetRoot(any(), any()); - Mockito.doReturn(Crosslink.EMPTY).when(attester).getPreviousCrosslink(any(), any()); + Mockito.doReturn(Hash32.ZERO).when(attester).getPreviousCrosslinkRoot(any(), any()); Mockito.doReturn(sourceRoot).when(attester).getSourceRoot(any(), any()); Attestation attestation = @@ -58,13 +58,13 @@ public void attestASlot() { AttestationData data = attestation.getData(); BeaconState state = initiallyObservedState.getLatestSlotState(); - Assert.assertEquals(state.getSlot(), data.getSlot()); + Assert.assertEquals(spec.get_current_epoch(state), data.getTargetEpoch()); Assert.assertEquals(shard, data.getShard()); Assert.assertEquals( - spec.signed_root(initiallyObservedState.getHead()), data.getBeaconBlockRoot()); + spec.signing_root(initiallyObservedState.getHead()), data.getBeaconBlockRoot()); Assert.assertEquals(targetRoot, data.getTargetRoot()); Assert.assertEquals(Hash32.ZERO, data.getCrosslinkDataRoot()); - Assert.assertEquals(Hash32.ZERO, data.getPreviousCrosslink().getCrosslinkDataRoot()); + Assert.assertEquals(Hash32.ZERO, data.getPreviousCrosslinkRoot()); Assert.assertEquals(state.getCurrentJustifiedEpoch(), data.getSourceEpoch()); Assert.assertEquals(sourceRoot, data.getSourceRoot()); @@ -81,12 +81,9 @@ public void attestASlot() { BLSSignature expectedSignature = signer.sign( spec.hash_tree_root(new AttestationDataAndCustodyBit(data, false)), - spec.get_domain( - state.getFork(), - spec.get_current_epoch(state), - SignatureDomains.ATTESTATION)); + spec.get_domain(state, SignatureDomains.ATTESTATION)); - Assert.assertEquals(expectedSignature, attestation.getAggregateSignature()); + Assert.assertEquals(expectedSignature, attestation.getSignature()); } private List getCommittee(int size) { diff --git a/validator/src/test/java/org/ethereum/beacon/validator/proposer/BeaconChainProposerTest.java b/validator/src/test/java/org/ethereum/beacon/validator/proposer/BeaconChainProposerTest.java index 8313bddfb..a08a0a008 100644 --- a/validator/src/test/java/org/ethereum/beacon/validator/proposer/BeaconChainProposerTest.java +++ b/validator/src/test/java/org/ethereum/beacon/validator/proposer/BeaconChainProposerTest.java @@ -23,7 +23,6 @@ import org.ethereum.beacon.core.operations.VoluntaryExit; import org.ethereum.beacon.core.operations.ProposerSlashing; import org.ethereum.beacon.core.operations.slashing.AttesterSlashing; -import org.ethereum.beacon.core.spec.SpecConstants; import org.ethereum.beacon.core.spec.SignatureDomains; import org.ethereum.beacon.core.state.Eth1Data; import org.ethereum.beacon.core.types.BLSSignature; @@ -42,7 +41,6 @@ import org.junit.Assert; import org.junit.Test; import org.mockito.Mockito; -import tech.pegasys.artemis.ethereum.core.Hash32; import tech.pegasys.artemis.util.uint.UInt64; public class BeaconChainProposerTest { @@ -109,12 +107,13 @@ public void proposeABlockWithOperations() { Mockito.verify(pendingOperations) .peekAggregatedAttestations( spec.getConstants().getMaxAttestations(), + initialState, initialState .getSlot() - .minus(spec.getConstants().getSlotsPerEpoch()), + .minusSat(spec.getConstants().getSlotsPerEpoch()), initialState .getSlot() - .minus(spec.getConstants().getMinAttestationInclusionDelay())); + .minusSat(spec.getConstants().getMinAttestationInclusionDelay())); Mockito.verify(pendingOperations) .peekProposerSlashings(spec.getConstants().getMaxProposerSlashings()); @@ -193,11 +192,8 @@ private boolean verifySignature( BLSSignature expectedSignature = signer.sign( - spec.signed_root(block), - spec.get_domain( - initialState.getFork(), - spec.get_current_epoch(initialState), - SignatureDomains.BEACON_BLOCK)); + spec.signing_root(block), + spec.get_domain(initialState, SignatureDomains.BEACON_PROPOSER)); return expectedSignature.equals(block.getSignature()); }