diff --git a/config/config.toml b/config/config.toml index 1095876ade2..63f8b1497d0 100644 --- a/config/config.toml +++ b/config/config.toml @@ -40,45 +40,129 @@ DepositSimulation = ["secp", "bls", "deposit_data", "events"] # Modify constants in Constants.java [constants] +# Minimal preset + + +# Misc +# --------------------------------------------------------------- + +# [customized] Just 8 shards for testing purposes SHARD_COUNT = 8 +# [customized] unsecure, but fast TARGET_COMMITTEE_SIZE = 4 -MAX_BALANCE_CHURN_QUOTIENT = 32 -MAX_INDICES_PER_SLASHABLE_VOTE = 4096 -MAX_EXIT_DEQUEUES_PER_EPOCH = 4 -SHUFFLE_ROUND_COUNT = 90 +# 2**12 (= 4,096) +MAX_INDICES_PER_ATTESTATION = 4096 +# 2**2 (= 4) +MIN_PER_EPOCH_CHURN_LIMIT = 4 +# 2**16 (= 65,536) +CHURN_LIMIT_QUOTIENT = 65536 +# Normalizes base rewards +BASE_REWARDS_PER_EPOCH = 5 +# [customized] Faster, but unsecure. +SHUFFLE_ROUND_COUNT = 10 + + +# Deposit contract +# --------------------------------------------------------------- +# **TBD** +DEPOSIT_CONTRACT_ADDRESS = '0x1234567890123456789012345678901234567890' +# 2**5 (= 32) DEPOSIT_CONTRACT_TREE_DEPTH = 32 + + +# Gwei values +# --------------------------------------------------------------- +# 2**0 * 10**9 (= 1,000,000,000) Gwei MIN_DEPOSIT_AMOUNT = 1000000000 -MAX_DEPOSIT_AMOUNT = 32000000000 -FORK_CHOICE_BALANCE_INCREMENT = 1000000000 +# 2**5 * 10**9 (= 32,000,000,000) Gwei +MAX_EFFECTIVE_BALANCE = 32000000000 +# 2**4 * 10**9 (= 16,000,000,000) Gwei EJECTION_BALANCE = 16000000000 -GENESIS_FORK_VERSION = 0 -GENESIS_SLOT = 4294967296 -GENESIS_EPOCH = 536870912 -GENESIS_START_SHARD = 0 +# 2**0 * 10**9 (= 1,000,000,000) Gwei +EFFECTIVE_BALANCE_INCREMENT = 1000000000 + + +# Initial values +# --------------------------------------------------------------- +GENESIS_FORK_VERSION = '0x00000000' +# 0, GENESIS_EPOCH is derived from this constant +GENESIS_SLOT = 0 +# 2**64 - 1 +FAR_FUTURE_EPOCH = 18446744073709551615 +BLS_WITHDRAWAL_PREFIX = 0 + + +# Time parameters +# --------------------------------------------------------------- +# 6 seconds 6 seconds SECONDS_PER_SLOT = 6 -MIN_ATTESTATION_INCLUSION_DELAY = 1 +# [customized] 2 slots +MIN_ATTESTATION_INCLUSION_DELAY = 2 +# [customized] fast epochs SLOTS_PER_EPOCH = 8 +# 2**0 (= 1) epochs MIN_SEED_LOOKAHEAD = 1 +# 2**2 (= 4) epochs ACTIVATION_EXIT_DELAY = 4 -EPOCHS_PER_ETH1_VOTING_PERIOD = 16 +# [customized] higher frequency new deposits from eth1 for testing +SLOTS_PER_ETH1_VOTING_PERIOD = 16 +# [customized] smaller state SLOTS_PER_HISTORICAL_ROOT = 64 +# 2**8 (= 256) epochs MIN_VALIDATOR_WITHDRAWABILITY_DELAY = 256 +# 2**11 (= 2,048) epochs PERSISTENT_COMMITTEE_PERIOD = 2048 +# 2**6 (= 64) epochs +MAX_EPOCHS_PER_CROSSLINK = 64 +# 2**2 (= 4) epochs +MIN_EPOCHS_TO_INACTIVITY_PENALTY = 4 +# [customized] 2**12 (= 4,096) epochs +EARLY_DERIVED_SECRET_PENALTY_MAX_FUTURE_EPOCHS = 4096 + + +# State list lengths +# --------------------------------------------------------------- +# [customized] smaller state LATEST_RANDAO_MIXES_LENGTH = 64 +# [customized] smaller state LATEST_ACTIVE_INDEX_ROOTS_LENGTH = 64 +# [customized] smaller state LATEST_SLASHED_EXIT_LENGTH = 64 -BASE_REWARD_QUOTIENT = 32 -WHISTLEBLOWER_REWARD_QUOTIENT = 512 -ATTESTATION_INCLUSION_REWARD_QUOTIENT = 8 -INACTIVITY_PENALTY_QUOTIENT = 16777216 -MIN_PENALTY_QUOTIENT = 32 + + +# Reward and penalty quotients +# --------------------------------------------------------------- +# 2**5 (= 32) +BASE_REWARD_FACTOR = 32 +# 2**9 (= 512) +WHISTLEBLOWING_REWARD_QUOTIENT = 512 +# 2**3 (= 8) +PROPOSER_REWARD_QUOTIENT = 8 +# 2**25 (= 33,554,432) +INACTIVITY_PENALTY_QUOTIENT = 33554432 +# 2**5 (= 32) +MIN_SLASHING_PENALTY_QUOTIENT = 32 + + +# Max operations per block +# --------------------------------------------------------------- +# 2**4 (= 16) MAX_PROPOSER_SLASHINGS = 16 +# 2**0 (= 1) MAX_ATTESTER_SLASHINGS = 1 +# 2**7 (= 128) MAX_ATTESTATIONS = 128 +# 2**4 (= 16) MAX_DEPOSITS = 16 +# 2**4 (= 16) MAX_VOLUNTARY_EXITS = 16 -MAX_TRANSFERS = 16 -DOMAIN_BEACON_BLOCK = 0 +# Originally 2**4 (= 16), disabled for now. +MAX_TRANSFERS = 0 + + +# Signature domains +# --------------------------------------------------------------- +DOMAIN_BEACON_PROPOSER = 0 DOMAIN_RANDAO = 1 DOMAIN_ATTESTATION = 2 DOMAIN_DEPOSIT = 3 diff --git a/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/Constants.java b/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/Constants.java index 895b9fd656b..d94e24003d4 100644 --- a/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/Constants.java +++ b/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/Constants.java @@ -27,41 +27,42 @@ public class Constants { // Misc public static int SHARD_COUNT = 1024; // 2^10 shards public static int TARGET_COMMITTEE_SIZE = 128; // 2^7 validators - public static int MAX_BALANCE_CHURN_QUOTIENT = 32; // 2^5 - public static int MAX_INDICES_PER_SLASHABLE_VOTE = 4096; // 2^12 votes - public static int MAX_EXIT_DEQUEUES_PER_EPOCH = 4; // 2^2 withdrawals + public static int MAX_INDICES_PER_ATTESTATION = 4096; // 2^5 + public static int MIN_PER_EPOCH_CHURN_LIMIT = 4; // 2^2 withdrawals + public static int CHURN_LIMIT_QUOTIENT = 65536; // 2^2 withdrawals + public static int BASE_REWARD_PER_EPOCH = 5; // 2^2 withdrawals public static int SHUFFLE_ROUND_COUNT = 90; // Deposit contract - public static String DEPOSIT_CONTRACT_ADDRESS = "0x0"; // This is TBD in the spec. public static int DEPOSIT_CONTRACT_TREE_DEPTH = 32; // 2^5 // Gwei values public static long MIN_DEPOSIT_AMOUNT = 1000000000L; // 2^0 * 1E9 Gwei - public static long MAX_DEPOSIT_AMOUNT = 32000000000L; // 2^5 * 1E9 Gwei - public static long FORK_CHOICE_BALANCE_INCREMENT = 1000000000L; // 2^0 * 1E9 Gwei + public static long MAX_EFFECTIVE_BALANCE = 32000000000L; // 2^5 * 1E9 Gwei public static long EJECTION_BALANCE = 16000000000L; // 2^4 * 1E9 Gwei + public static long EFFECTIVE_BALANCE_INCREMENT = 1000000000L; // 2^0 * 1E9 Gwei + + // Initial values + public static long GENESIS_SLOT = 0; // 2^32 + public static long GENESIS_EPOCH = 0; + public static long GENESIS_FORK_VERSION = 0; + public static UnsignedLong FAR_FUTURE_EPOCH = UnsignedLong.MAX_VALUE; + public static Bytes32 ZERO_HASH = Bytes32.ZERO; // TODO confirm if equals to b'\x00' * 32 + public static int BLS_WITHDRAWAL_PREFIX_BYTE = 0; // Time parameters - public static int SECONDS_PER_SLOT = 6; // 6 seconds public static int MIN_ATTESTATION_INCLUSION_DELAY = 4; // 2^2 slots public static int SLOTS_PER_EPOCH = 64; // 2^6 slots public static int MIN_SEED_LOOKAHEAD = 1; // 2^0 epochs (6.4 minutes) public static int ACTIVATION_EXIT_DELAY = 4; // 2^2 epochs (25.6 minutes) - public static int EPOCHS_PER_ETH1_VOTING_PERIOD = 16; // 2^4 epochs (~1.7 hours) + public static int SLOTS_PER_ETH1_VOTING_PERIOD = 1024; // 2^4 epochs (~1.7 hours) public static int SLOTS_PER_HISTORICAL_ROOT = 8192; // 2^13 slots (~13 hours) public static int MIN_VALIDATOR_WITHDRAWABILITY_DELAY = 256; // 2^8 epochs (~27 hours) public static int PERSISTENT_COMMITTEE_PERIOD = 2048; // 2^11 epochs (~9 days) + public static int MAX_EPOCHS_PER_CROSSLINK = 64; // 2^11 epochs (~9 days) + public static int MIN_EPOCHS_TO_INACTIVITY_PENALTY = 4; // 2^11 epochs (~9 days) - // Initial values - public static int GENESIS_FORK_VERSION = 0; - public static long GENESIS_SLOT = 4294967296L; // 2^32 - public static long GENESIS_EPOCH = slot_to_epoch(GENESIS_SLOT); - public static long GENESIS_START_SHARD = 0; - public static UnsignedLong FAR_FUTURE_EPOCH = UnsignedLong.MAX_VALUE; - public static Bytes32 ZERO_HASH = Bytes32.ZERO; - public static BLSSignature EMPTY_SIGNATURE = BLSSignature.empty(); - public static Bytes BLS_WITHDRAWAL_PREFIX_BYTE = Bytes.EMPTY; + public static int SECONDS_PER_SLOT = 6; // removed in 7.1 main spec for some reason but keep for now // State list lengths public static int LATEST_RANDAO_MIXES_LENGTH = 8192; // 2^13 epochs (~36 days) @@ -69,11 +70,11 @@ public class Constants { public static int LATEST_SLASHED_EXIT_LENGTH = 8192; // 2^13 epochs (~36 days) // Reward and penalty quotients - public static int BASE_REWARD_QUOTIENT = 32; // 2^5 - public static int WHISTLEBLOWER_REWARD_QUOTIENT = 512; // 2^9 - public static int ATTESTATION_INCLUSION_REWARD_QUOTIENT = 8; // 2^3 - public static int INACTIVITY_PENALTY_QUOTIENT = 16777216; // 2^24 - public static int MIN_PENALTY_QUOTIENT = 32; // 2^5 + public static int BASE_REWARD_FACTOR = 32; // 2^5 + public static int WHISTLEBLOWING_REWARD_QUOTIENT = 512; // 2^9 + public static int PROPOSER_REWARD_QUOTIENT = 8; // 2^3 + public static int INACTIVITY_PENALTY_QUOTIENT = 33554432; // 2^25 + public static int MIN_SLASHING_PENALTY_QUOTIENT = 32; // 2^5 // Max transactions per block public static int MAX_PROPOSER_SLASHINGS = 16; // 2^4 @@ -84,7 +85,7 @@ public class Constants { public static int MAX_TRANSFERS = 16; // 2^4 // Signature domains - public static int DOMAIN_BEACON_BLOCK = 0; + public static int DOMAIN_BEACON_PROPOSER = 0; public static int DOMAIN_RANDAO = 1; public static int DOMAIN_ATTESTATION = 2; public static int DOMAIN_DEPOSIT = 3; diff --git a/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/blocks/BeaconBlock.java b/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/blocks/BeaconBlock.java index 1c0b3580067..95b5d2c993a 100644 --- a/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/blocks/BeaconBlock.java +++ b/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/blocks/BeaconBlock.java @@ -26,7 +26,7 @@ public final class BeaconBlock { // Header private long slot; - private Bytes32 previous_block_root; + private Bytes32 parent_root; private Bytes32 state_root; // Body @@ -37,12 +37,12 @@ public final class BeaconBlock { public BeaconBlock( long slot, - Bytes32 previous_block_root, + Bytes32 parent_root, Bytes32 state_root, BeaconBlockBody body, BLSSignature signature) { this.slot = slot; - this.previous_block_root = previous_block_root; + this.parent_root = parent_root; this.state_root = state_root; this.body = body; this.signature = signature; @@ -64,7 +64,7 @@ public Bytes toBytes() { return SSZ.encode( writer -> { writer.writeUInt64(slot); - writer.writeFixedBytes(32, previous_block_root); + writer.writeFixedBytes(32, parent_root); writer.writeFixedBytes(32, state_root); writer.writeBytes(body.toBytes()); writer.writeBytes(signature.toBytes()); @@ -73,7 +73,7 @@ public Bytes toBytes() { @Override public int hashCode() { - return Objects.hash(slot, previous_block_root, state_root, body, signature); + return Objects.hash(slot, parent_root, state_root, body, signature); } @Override @@ -92,7 +92,7 @@ public boolean equals(Object obj) { BeaconBlock other = (BeaconBlock) obj; return slot == other.getSlot() - && Objects.equals(this.getPrevious_block_root(), other.getPrevious_block_root()) + && Objects.equals(this.getParent_root(), other.getParent_root()) && Objects.equals(this.getState_root(), other.getState_root()) && Objects.equals(this.getBody(), other.getBody()) && Objects.equals(this.getSignature(), other.getSignature()); @@ -123,12 +123,12 @@ public void setState_root(Bytes32 state_root) { this.state_root = state_root; } - public Bytes32 getPrevious_block_root() { - return previous_block_root; + public Bytes32 getParent_root() { + return parent_root; } - public void setPrevious_block_root(Bytes32 previous_block_root) { - this.previous_block_root = previous_block_root; + public void setParent_root(Bytes32 parent_root) { + this.parent_root = parent_root; } public long getSlot() { @@ -149,7 +149,7 @@ public Bytes32 signed_root(String truncation_param) { HashTreeUtil.merkleize( Arrays.asList( HashTreeUtil.hash_tree_root(SSZTypes.BASIC, SSZ.encodeUInt64(slot)), - HashTreeUtil.hash_tree_root(SSZTypes.TUPLE_OF_BASIC, previous_block_root), + HashTreeUtil.hash_tree_root(SSZTypes.TUPLE_OF_BASIC, parent_root), HashTreeUtil.hash_tree_root(SSZTypes.TUPLE_OF_BASIC, state_root), body.hash_tree_root()))); } @@ -158,7 +158,7 @@ public Bytes32 hash_tree_root() { return HashTreeUtil.merkleize( Arrays.asList( HashTreeUtil.hash_tree_root(SSZTypes.BASIC, SSZ.encodeUInt64(slot)), - HashTreeUtil.hash_tree_root(SSZTypes.TUPLE_OF_BASIC, previous_block_root), + HashTreeUtil.hash_tree_root(SSZTypes.TUPLE_OF_BASIC, parent_root), HashTreeUtil.hash_tree_root(SSZTypes.TUPLE_OF_BASIC, state_root), body.hash_tree_root(), HashTreeUtil.hash_tree_root(SSZTypes.TUPLE_OF_BASIC, signature.toBytes()))); diff --git a/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/blocks/BeaconBlockBody.java b/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/blocks/BeaconBlockBody.java index 90c7b055028..8f859127df2 100644 --- a/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/blocks/BeaconBlockBody.java +++ b/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/blocks/BeaconBlockBody.java @@ -34,6 +34,7 @@ public class BeaconBlockBody { private BLSSignature randao_reveal; private Eth1Data eth1_data; + private Bytes32 graffiti; private List proposer_slashings; private List attester_slashings; private List attestations; @@ -44,6 +45,7 @@ public class BeaconBlockBody { public BeaconBlockBody( BLSSignature randao_reveal, Eth1Data eth1_data, + Bytes32 graffiti, List proposer_slashings, List attester_slashings, List attestations, @@ -52,6 +54,7 @@ public BeaconBlockBody( List transfers) { this.randao_reveal = randao_reveal; this.eth1_data = eth1_data; + this.graffiti = graffiti; this.proposer_slashings = proposer_slashings; this.attester_slashings = attester_slashings; this.attestations = attestations; @@ -67,6 +70,7 @@ public static BeaconBlockBody fromBytes(Bytes bytes) { new BeaconBlockBody( BLSSignature.fromBytes(reader.readBytes()), Eth1Data.fromBytes(reader.readBytes()), + Bytes32.wrap(reader.readFixedBytes(32)), reader.readBytesList().stream() .map(ProposerSlashing::fromBytes) .collect(Collectors.toList()), @@ -105,6 +109,7 @@ public Bytes toBytes() { writer -> { writer.writeBytes(randao_reveal.toBytes()); writer.writeBytes(eth1_data.toBytes()); + writer.writeFixedBytes(32, graffiti); writer.writeBytesList(proposerSlashingsBytes); writer.writeBytesList(attesterSlashingsBytes); writer.writeBytesList(attestationsBytes); @@ -119,6 +124,7 @@ public int hashCode() { return Objects.hash( randao_reveal, eth1_data, + graffiti, proposer_slashings, attester_slashings, attestations, @@ -144,6 +150,7 @@ public boolean equals(Object obj) { BeaconBlockBody other = (BeaconBlockBody) obj; return Objects.equals(this.getRandao_reveal(), other.getRandao_reveal()) && Objects.equals(this.getEth1_data(), other.getEth1_data()) + && Objects.equals(this.getGraffiti(), other.getGraffiti()) && Objects.equals(this.getProposer_slashings(), other.getProposer_slashings()) && Objects.equals(this.getAttester_slashings(), other.getAttester_slashings()) && Objects.equals(this.getAttestations(), other.getAttestations()) @@ -169,6 +176,14 @@ public void setEth1_data(Eth1Data eth1_data) { this.eth1_data = eth1_data; } + public Bytes32 getGraffiti() { + return graffiti; + } + + public void setGraffiti(Bytes32 graffiti) { + this.graffiti = graffiti; + } + public List getAttestations() { return attestations; } @@ -222,6 +237,7 @@ public Bytes32 hash_tree_root() { Arrays.asList( HashTreeUtil.hash_tree_root(SSZTypes.TUPLE_OF_BASIC, randao_reveal.toBytes()), eth1_data.hash_tree_root(), + HashTreeUtil.hash_tree_root(SSZTypes.TUPLE_OF_BASIC, graffiti), HashTreeUtil.hash_tree_root(SSZTypes.LIST_OF_COMPOSITE, proposer_slashings), HashTreeUtil.hash_tree_root(SSZTypes.LIST_OF_COMPOSITE, attester_slashings), HashTreeUtil.hash_tree_root(SSZTypes.LIST_OF_COMPOSITE, attestations), diff --git a/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/blocks/BeaconBlockHeader.java b/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/blocks/BeaconBlockHeader.java index e70006020e5..3a12992a014 100644 --- a/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/blocks/BeaconBlockHeader.java +++ b/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/blocks/BeaconBlockHeader.java @@ -26,21 +26,21 @@ public class BeaconBlockHeader { private UnsignedLong slot; - private Bytes32 previous_block_root; + private Bytes32 parent_root; private Bytes32 state_root; - private Bytes32 block_body_root; + private Bytes32 body_root; private BLSSignature signature; public BeaconBlockHeader( UnsignedLong slot, - Bytes32 previous_block_root, + Bytes32 parent_root, Bytes32 state_root, - Bytes32 block_body_root, + Bytes32 body_root, BLSSignature signature) { this.slot = slot; - this.previous_block_root = previous_block_root; + this.parent_root = parent_root; this.state_root = state_root; - this.block_body_root = block_body_root; + this.body_root = body_root; this.signature = signature; } @@ -60,16 +60,16 @@ public Bytes toBytes() { return SSZ.encode( writer -> { writer.writeUInt64(slot.longValue()); - writer.writeFixedBytes(32, previous_block_root); + writer.writeFixedBytes(32, parent_root); writer.writeFixedBytes(32, state_root); - writer.writeFixedBytes(32, block_body_root); + writer.writeFixedBytes(32, body_root); writer.writeBytes(signature.toBytes()); }); } @Override public int hashCode() { - return Objects.hash(slot, previous_block_root, state_root, block_body_root, signature); + return Objects.hash(slot, parent_root, state_root, body_root, signature); } @Override @@ -88,9 +88,9 @@ public boolean equals(Object obj) { BeaconBlockHeader other = (BeaconBlockHeader) obj; return Objects.equals(this.getSlot(), other.getSlot()) - && Objects.equals(this.getPrevious_block_root(), other.getPrevious_block_root()) + && Objects.equals(this.getParent_root(), other.getParent_root()) && Objects.equals(this.getState_root(), other.getState_root()) - && Objects.equals(this.getBlock_body_root(), other.getBlock_body_root()) + && Objects.equals(this.getBody_root(), other.getBody_root()) && Objects.equals(this.getSignature(), other.getSignature()); } @@ -103,12 +103,12 @@ public void setSlot(UnsignedLong slot) { this.slot = slot; } - public Bytes32 getPrevious_block_root() { - return previous_block_root; + public Bytes32 getParent_root() { + return parent_root; } - public void setPrevious_block_root(Bytes32 previous_block_root) { - this.previous_block_root = previous_block_root; + public void setParent_root(Bytes32 parent_root) { + this.parent_root = parent_root; } public Bytes32 getState_root() { @@ -119,12 +119,12 @@ public void setState_root(Bytes32 state_root) { this.state_root = state_root; } - public Bytes32 getBlock_body_root() { - return block_body_root; + public Bytes32 getBody_root() { + return body_root; } - public void setBlock_block_root(Bytes32 block_body_root) { - this.block_body_root = block_body_root; + public void setBody_root(Bytes32 body_root) { + this.body_root = body_root; } public BLSSignature getSignature() { @@ -145,18 +145,18 @@ public Bytes32 signed_root(String truncation_param) { HashTreeUtil.merkleize( Arrays.asList( HashTreeUtil.hash_tree_root(SSZTypes.BASIC, SSZ.encodeUInt64(slot.longValue())), - HashTreeUtil.hash_tree_root(SSZTypes.TUPLE_OF_BASIC, previous_block_root), + HashTreeUtil.hash_tree_root(SSZTypes.TUPLE_OF_BASIC, parent_root), HashTreeUtil.hash_tree_root(SSZTypes.TUPLE_OF_BASIC, state_root), - HashTreeUtil.hash_tree_root(SSZTypes.TUPLE_OF_BASIC, block_body_root)))); + HashTreeUtil.hash_tree_root(SSZTypes.TUPLE_OF_BASIC, body_root)))); } public Bytes32 hash_tree_root() { return HashTreeUtil.merkleize( Arrays.asList( HashTreeUtil.hash_tree_root(SSZTypes.BASIC, SSZ.encodeUInt64(slot.longValue())), - HashTreeUtil.hash_tree_root(SSZTypes.TUPLE_OF_BASIC, previous_block_root), + HashTreeUtil.hash_tree_root(SSZTypes.TUPLE_OF_BASIC, parent_root), HashTreeUtil.hash_tree_root(SSZTypes.TUPLE_OF_BASIC, state_root), - HashTreeUtil.hash_tree_root(SSZTypes.TUPLE_OF_BASIC, block_body_root), + HashTreeUtil.hash_tree_root(SSZTypes.TUPLE_OF_BASIC, body_root), HashTreeUtil.hash_tree_root(SSZTypes.TUPLE_OF_BASIC, signature.toBytes()))); } } diff --git a/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/blocks/Eth1Data.java b/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/blocks/Eth1Data.java index e4250025551..3f72b84fe52 100644 --- a/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/blocks/Eth1Data.java +++ b/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/blocks/Eth1Data.java @@ -15,6 +15,8 @@ import java.util.Arrays; import java.util.Objects; + +import com.google.common.primitives.UnsignedLong; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.ssz.SSZ; @@ -24,15 +26,18 @@ public final class Eth1Data { private Bytes32 deposit_root; + private UnsignedLong deposit_count; private Bytes32 block_hash; - public Eth1Data(Bytes32 deposit_root, Bytes32 block_hash) { + public Eth1Data(Bytes32 deposit_root, UnsignedLong deposit_count, Bytes32 block_hash) { this.deposit_root = deposit_root; + this.deposit_count = deposit_count; this.block_hash = block_hash; } public Eth1Data(Eth1Data eth1Data) { this.deposit_root = eth1Data.getDeposit_root(); + this.deposit_count = eth1Data.getDeposit_count(); this.block_hash = eth1Data.getBlock_hash(); } @@ -41,20 +46,23 @@ public static Eth1Data fromBytes(Bytes bytes) { bytes, reader -> new Eth1Data( - Bytes32.wrap(reader.readFixedBytes(32)), Bytes32.wrap(reader.readFixedBytes(32)))); + Bytes32.wrap(reader.readFixedBytes(32)), + UnsignedLong.fromLongBits(reader.readUInt64()), + Bytes32.wrap(reader.readFixedBytes(32)))); } public Bytes toBytes() { return SSZ.encode( writer -> { writer.writeFixedBytes(32, deposit_root); + writer.writeUInt64(deposit_count.longValue()); writer.writeFixedBytes(32, block_hash); }); } @Override public int hashCode() { - return Objects.hash(deposit_root, block_hash); + return Objects.hash(deposit_root, deposit_count, block_hash); } @Override @@ -73,6 +81,7 @@ public boolean equals(Object obj) { Eth1Data other = (Eth1Data) obj; return Objects.equals(this.getDeposit_root(), other.getDeposit_root()) + && Objects.equals(this.getDeposit_count(), other.getDeposit_count()) && Objects.equals(this.getBlock_hash(), other.getBlock_hash()); } @@ -86,6 +95,14 @@ public void setDeposit_root(Bytes32 deposit_root) { this.deposit_root = deposit_root; } + public UnsignedLong getDeposit_count() { + return deposit_count; + } + + public void setDeposit_count(UnsignedLong deposit_count) { + this.deposit_count = deposit_count; + } + /** @return the block_hash */ public Bytes32 getBlock_hash() { return block_hash; @@ -100,6 +117,8 @@ public Bytes32 hash_tree_root() { return HashTreeUtil.merkleize( Arrays.asList( HashTreeUtil.hash_tree_root(SSZTypes.TUPLE_OF_BASIC, deposit_root), + HashTreeUtil.hash_tree_root( + SSZTypes.BASIC, SSZ.encodeUInt64(deposit_count.longValue())), HashTreeUtil.hash_tree_root(SSZTypes.TUPLE_OF_BASIC, block_hash))); } } diff --git a/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/operations/AttestationData.java b/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/operations/AttestationData.java index bf0bdc258fd..007510880b0 100644 --- a/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/operations/AttestationData.java +++ b/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/operations/AttestationData.java @@ -26,47 +26,39 @@ public class AttestationData { // LMD GHOST vote - private UnsignedLong slot; private Bytes32 beacon_block_root; // FFG vote private UnsignedLong source_epoch; private Bytes32 source_root; + private UnsignedLong target_epoch; private Bytes32 target_root; // Crosslink vote - private UnsignedLong shard; - private Crosslink previous_crosslink; - private Bytes32 crosslink_data_root; + private Crosslink crosslink; public AttestationData( - UnsignedLong slot, Bytes32 beacon_block_root, UnsignedLong source_epoch, Bytes32 source_root, + UnsignedLong target_epoch, Bytes32 target_root, - UnsignedLong shard, - Crosslink previous_crosslink, - Bytes32 crosslink_data_root) { - this.slot = slot; + Crosslink crosslink) { this.beacon_block_root = beacon_block_root; this.source_epoch = source_epoch; this.source_root = source_root; + this.target_epoch = target_epoch; this.target_root = target_root; - this.shard = shard; - this.previous_crosslink = previous_crosslink; - this.crosslink_data_root = crosslink_data_root; + this.crosslink = crosslink; } public AttestationData(AttestationData attestationData) { - this.slot = attestationData.getSlot(); this.beacon_block_root = attestationData.getBeacon_block_root(); this.source_epoch = attestationData.getSource_epoch(); this.source_root = attestationData.getSource_root(); + this.target_epoch = attestationData.getTarget_epoch(); this.target_root = attestationData.getTarget_root(); - this.shard = attestationData.getShard(); - this.previous_crosslink = new Crosslink(attestationData.getPrevious_crosslink()); - this.crosslink_data_root = attestationData.getCrosslink_data_root(); + this.crosslink = new Crosslink(attestationData.getCrosslink()); } public static AttestationData fromBytes(Bytes bytes) { @@ -74,41 +66,35 @@ public static AttestationData fromBytes(Bytes bytes) { bytes, reader -> new AttestationData( - UnsignedLong.fromLongBits(reader.readUInt64()), Bytes32.wrap(reader.readFixedBytes(32)), UnsignedLong.fromLongBits(reader.readUInt64()), Bytes32.wrap(reader.readFixedBytes(32)), - Bytes32.wrap(reader.readFixedBytes(32)), UnsignedLong.fromLongBits(reader.readUInt64()), - Crosslink.fromBytes(reader.readBytes()), - Bytes32.wrap(reader.readFixedBytes(32)))); + Bytes32.wrap(reader.readFixedBytes(32)), + Crosslink.fromBytes(reader.readBytes()))); } public Bytes toBytes() { return SSZ.encode( writer -> { - writer.writeUInt64(slot.longValue()); writer.writeFixedBytes(32, beacon_block_root); writer.writeUInt64(source_epoch.longValue()); writer.writeFixedBytes(32, source_root); + writer.writeUInt64(target_epoch.longValue()); writer.writeFixedBytes(32, target_root); - writer.writeUInt64(shard.longValue()); - writer.writeBytes(previous_crosslink.toBytes()); - writer.writeFixedBytes(32, crosslink_data_root); + writer.writeBytes(crosslink.toBytes()); }); } @Override public int hashCode() { return Objects.hash( - slot, - beacon_block_root, + beacon_block_root, source_epoch, source_root, + target_epoch, target_root, - shard, - previous_crosslink, - crosslink_data_root); + crosslink); } @Override @@ -126,24 +112,15 @@ public boolean equals(Object obj) { } AttestationData other = (AttestationData) obj; - return Objects.equals(this.getSlot(), other.getSlot()) - && Objects.equals(this.getBeacon_block_root(), other.getBeacon_block_root()) + return Objects.equals(this.getBeacon_block_root(), other.getBeacon_block_root()) && Objects.equals(this.getSource_epoch(), other.getSource_epoch()) && Objects.equals(this.getSource_root(), other.getSource_root()) + && Objects.equals(this.getTarget_epoch(), other.getTarget_epoch()) && Objects.equals(this.getTarget_root(), other.getTarget_root()) - && Objects.equals(this.getShard(), other.getShard()) - && Objects.equals(this.getPrevious_crosslink(), other.getPrevious_crosslink()) - && Objects.equals(this.getCrosslink_data_root(), other.getCrosslink_data_root()); + && Objects.equals(this.getCrosslink(), other.getCrosslink()); } /** ******************* * GETTERS & SETTERS * * ******************* */ - public UnsignedLong getSlot() { - return slot; - } - - public void setSlot(UnsignedLong slot) { - this.slot = slot; - } public Bytes32 getBeacon_block_root() { return beacon_block_root; @@ -169,48 +146,38 @@ public void setSource_root(Bytes32 source_root) { this.source_root = source_root; } - public Bytes32 getTarget_root() { - return target_root; - } - - public void setTarget_root(Bytes32 target_root) { - this.target_root = target_root; - } - - public UnsignedLong getShard() { - return shard; + public UnsignedLong getTarget_epoch() { + return target_epoch; } - public void setShard(UnsignedLong shard) { - this.shard = shard; + public void setTarget_epoch(UnsignedLong target_epoch) { + this.target_epoch = target_epoch; } - public Crosslink getPrevious_crosslink() { - return previous_crosslink; + public Bytes32 getTarget_root() { + return target_root; } - public void setPrevious_crosslink(Crosslink previous_crosslink) { - this.previous_crosslink = previous_crosslink; + public void setTarget_root(Bytes32 target_root) { + this.target_root = target_root; } - public Bytes32 getCrosslink_data_root() { - return crosslink_data_root; + public Crosslink getCrosslink() { + return crosslink; } - public void setCrosslink_data_root(Bytes32 crosslink_data_root) { - this.crosslink_data_root = crosslink_data_root; + public void setCrosslink(Crosslink crosslink) { + this.crosslink = crosslink; } public Bytes32 hash_tree_root() { return HashTreeUtil.merkleize( Arrays.asList( - HashTreeUtil.hash_tree_root(SSZTypes.BASIC, SSZ.encodeUInt64(slot.longValue())), HashTreeUtil.hash_tree_root(SSZTypes.TUPLE_OF_BASIC, beacon_block_root), HashTreeUtil.hash_tree_root(SSZTypes.BASIC, SSZ.encodeUInt64(source_epoch.longValue())), HashTreeUtil.hash_tree_root(SSZTypes.TUPLE_OF_BASIC, source_root), + HashTreeUtil.hash_tree_root(SSZTypes.BASIC, SSZ.encodeUInt64(target_epoch.longValue())), HashTreeUtil.hash_tree_root(SSZTypes.TUPLE_OF_BASIC, target_root), - HashTreeUtil.hash_tree_root(SSZTypes.BASIC, SSZ.encodeUInt64(shard.longValue())), - previous_crosslink.hash_tree_root(), - HashTreeUtil.hash_tree_root(SSZTypes.TUPLE_OF_BASIC, crosslink_data_root))); + crosslink.hash_tree_root())); } } diff --git a/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/operations/AttesterSlashing.java b/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/operations/AttesterSlashing.java index ea887d19b10..e205b7f0a4e 100644 --- a/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/operations/AttesterSlashing.java +++ b/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/operations/AttesterSlashing.java @@ -15,6 +15,8 @@ import java.util.Arrays; import java.util.Objects; + +import jnr.ffi.annotations.In; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.ssz.SSZ; @@ -23,13 +25,13 @@ public class AttesterSlashing implements Merkleizable { - private SlashableAttestation slashable_attestation_1; - private SlashableAttestation slashable_attestation_2; + private IndexedAttestation attestation_1; + private IndexedAttestation attestation_2; public AttesterSlashing( - SlashableAttestation slashable_attestation_1, SlashableAttestation slashable_attestation_2) { - this.slashable_attestation_1 = slashable_attestation_1; - this.slashable_attestation_2 = slashable_attestation_2; + IndexedAttestation attestation_1, IndexedAttestation attestation_2) { + this.attestation_1 = attestation_1; + this.attestation_2 = attestation_2; } public static AttesterSlashing fromBytes(Bytes bytes) { @@ -37,21 +39,21 @@ public static AttesterSlashing fromBytes(Bytes bytes) { bytes, reader -> new AttesterSlashing( - SlashableAttestation.fromBytes(reader.readBytes()), - SlashableAttestation.fromBytes(reader.readBytes()))); + IndexedAttestation.fromBytes(reader.readBytes()), + IndexedAttestation.fromBytes(reader.readBytes()))); } public Bytes toBytes() { return SSZ.encode( writer -> { - writer.writeBytes(slashable_attestation_1.toBytes()); - writer.writeBytes(slashable_attestation_2.toBytes()); + writer.writeBytes(attestation_1.toBytes()); + writer.writeBytes(attestation_2.toBytes()); }); } @Override public int hashCode() { - return Objects.hash(slashable_attestation_1, slashable_attestation_2); + return Objects.hash(attestation_1, attestation_2); } @Override @@ -69,31 +71,31 @@ public boolean equals(Object obj) { } AttesterSlashing other = (AttesterSlashing) obj; - return Objects.equals(this.getSlashable_attestation_1(), other.getSlashable_attestation_1()) - && Objects.equals(this.getSlashable_attestation_2(), other.getSlashable_attestation_2()); + return Objects.equals(this.getAttestation_1(), other.getAttestation_1()) + && Objects.equals(this.getAttestation_2(), other.getAttestation_2()); } /** ******************* * GETTERS & SETTERS * * ******************* */ - public SlashableAttestation getSlashable_attestation_1() { - return slashable_attestation_1; + public IndexedAttestation getAttestation_1() { + return attestation_1; } - public void setSlashable_attestation_1(SlashableAttestation slashable_attestation_1) { - this.slashable_attestation_1 = slashable_attestation_1; + public void setAttestation_1(IndexedAttestation attestation_1) { + this.attestation_1 = attestation_1; } - public SlashableAttestation getSlashable_attestation_2() { - return slashable_attestation_2; + public IndexedAttestation getAttestation_2() { + return attestation_2; } - public void setSlashable_attestation_2(SlashableAttestation slashable_attestation_2) { - this.slashable_attestation_2 = slashable_attestation_2; + public void setAttestation_2(IndexedAttestation attestation_2) { + this.attestation_2 = attestation_2; } @Override public Bytes32 hash_tree_root() { return HashTreeUtil.merkleize( Arrays.asList( - slashable_attestation_1.hash_tree_root(), slashable_attestation_2.hash_tree_root())); + attestation_1.hash_tree_root(), attestation_2.hash_tree_root())); } } diff --git a/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/operations/Deposit.java b/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/operations/Deposit.java index 656dd352322..57ca2dfa0bb 100644 --- a/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/operations/Deposit.java +++ b/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/operations/Deposit.java @@ -31,12 +31,10 @@ public class Deposit implements Merkleizable { private List proof; // Bounded by DEPOSIT_CONTRACT_TREE_DEPTH - private UnsignedLong index; private DepositData deposit_data; - public Deposit(List proof, UnsignedLong index, DepositData deposit_data) { + public Deposit(List proof, DepositData deposit_data) { this.proof = proof; - this.index = index; this.deposit_data = deposit_data; } @@ -48,7 +46,6 @@ public static Deposit fromBytes(Bytes bytes) { reader.readFixedBytesList((long) Constants.DEPOSIT_CONTRACT_TREE_DEPTH, 32).stream() .map(Bytes32::wrap) .collect(Collectors.toList()), - UnsignedLong.fromLongBits(reader.readUInt64()), DepositData.fromBytes(reader.readBytes()))); } @@ -68,14 +65,13 @@ public Bytes toBytes() { writer -> { writer.writeFixedBytesList( (long) Constants.DEPOSIT_CONTRACT_TREE_DEPTH, 32, filledProofList); - writer.writeUInt64(index.longValue()); writer.writeBytes(deposit_data.toBytes()); }); } @Override public int hashCode() { - return Objects.hash(proof, index, deposit_data); + return Objects.hash(proof, deposit_data); } @Override @@ -94,7 +90,6 @@ public boolean equals(Object obj) { Deposit other = (Deposit) obj; return Objects.equals(this.getProof(), other.getProof()) - && Objects.equals(this.getIndex(), other.getIndex()) && Objects.equals(this.getDeposit_data(), other.getDeposit_data()); } @@ -107,14 +102,6 @@ public void setProof(List branch) { this.proof = branch; } - public UnsignedLong getIndex() { - return index; - } - - public void setIndex(UnsignedLong index) { - this.index = index; - } - public DepositData getDeposit_data() { return deposit_data; } @@ -129,7 +116,6 @@ public Bytes32 hash_tree_root() { Arrays.asList( // TODO Look at this - is this a TUPLE_OF_COMPOSITE HashTreeUtil.hash_tree_root(SSZTypes.BASIC, proof.toArray(new Bytes32[0])), - HashTreeUtil.hash_tree_root(SSZTypes.BASIC, SSZ.encodeUInt64(index.longValue())), deposit_data.hash_tree_root())); } } diff --git a/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/operations/DepositData.java b/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/operations/DepositData.java index 70d119f66a0..7b43cc86443 100644 --- a/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/operations/DepositData.java +++ b/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/operations/DepositData.java @@ -19,19 +19,23 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.ssz.SSZ; +import tech.pegasys.artemis.util.bls.BLSPublicKey; +import tech.pegasys.artemis.util.bls.BLSSignature; import tech.pegasys.artemis.util.hashtree.HashTreeUtil; import tech.pegasys.artemis.util.hashtree.HashTreeUtil.SSZTypes; public class DepositData { + private BLSPublicKey pubkey; + private Bytes32 withdrawal_credentials; private UnsignedLong amount; - private UnsignedLong timestamp; - private DepositInput deposit_input; + private BLSSignature signature; - public DepositData(UnsignedLong amount, UnsignedLong timestamp, DepositInput deposit_input) { + public DepositData(BLSPublicKey pubkey, Bytes32 withdrawal_credentials, UnsignedLong amount, BLSSignature signature) { + this.pubkey = pubkey; + this.withdrawal_credentials = withdrawal_credentials; this.amount = amount; - this.timestamp = timestamp; - this.deposit_input = deposit_input; + this.signature = signature; } public static DepositData fromBytes(Bytes bytes) { @@ -39,34 +43,35 @@ public static DepositData fromBytes(Bytes bytes) { bytes, reader -> new DepositData( + BLSPublicKey.fromBytes(reader.readBytes()), + Bytes32.wrap(reader.readFixedBytes(32)), UnsignedLong.fromLongBits(reader.readUInt64()), - UnsignedLong.fromLongBits(reader.readUInt64()), - DepositInput.fromBytes(reader.readBytes()))); + BLSSignature.fromBytes(reader.readBytes()))); + } public Bytes toBytes() { return SSZ.encode( writer -> { + writer.writeBytes(pubkey.toBytes()); + writer.writeFixedBytes(32, withdrawal_credentials); writer.writeUInt64(amount.longValue()); - writer.writeUInt64(timestamp.longValue()); - writer.writeBytes(deposit_input.toBytes()); + writer.writeBytes(signature.toBytes()); }); } + // TODO: check if this is correct public Bytes serialize() { - Bytes deposit_data = - Bytes.wrap( + return Bytes.wrap( + pubkey.getPublicKey().toBytesCompressed(), + withdrawal_credentials, Bytes.ofUnsignedLong(amount.longValue()), - deposit_input.getWithdrawal_credentials(), - deposit_input.getPubkey().getPublicKey().toBytesCompressed()); - return Bytes.wrap( - deposit_input.getProof_of_possession().getSignature().toBytesCompressed(), deposit_data) - .reverse(); + signature.toBytes()); } @Override public int hashCode() { - return Objects.hash(amount, timestamp, deposit_input); + return Objects.hash(pubkey, withdrawal_credentials, amount, signature); } @Override @@ -84,18 +89,28 @@ public boolean equals(Object obj) { } DepositData other = (DepositData) obj; - return Objects.equals(this.getAmount(), other.getAmount()) - && Objects.equals(this.getTimestamp(), other.getTimestamp()) - && Objects.equals(this.getDeposit_input(), other.getDeposit_input()); + return Objects.equals(this.getPubkey(), other.getPubkey()) + && Objects.equals(this.getWithdrawal_credentials(), other.getWithdrawal_credentials()) + && Objects.equals(this.getAmount(), other.getAmount()) + && Objects.equals(this.getSignature(), other.getSignature()); } /** ******************* * GETTERS & SETTERS * * ******************* */ - public DepositInput getDeposit_input() { - return deposit_input; + + public BLSPublicKey getPubkey() { + return pubkey; + } + + public void setPubkey(BLSPublicKey pubkey) { + this.pubkey = pubkey; + } + + public Bytes32 getWithdrawal_credentials() { + return withdrawal_credentials; } - public void setDeposit_input(DepositInput deposit_input) { - this.deposit_input = deposit_input; + public void setWithdrawal_credentials(Bytes32 withdrawal_credentials) { + this.withdrawal_credentials = withdrawal_credentials; } public UnsignedLong getAmount() { @@ -106,19 +121,19 @@ public void setAmount(UnsignedLong amount) { this.amount = amount; } - public UnsignedLong getTimestamp() { - return timestamp; + public BLSSignature getSignature() { + return signature; } - public void setTimestamp(UnsignedLong timestamp) { - this.timestamp = timestamp; + public void setSignature(BLSSignature signature) { + this.signature = signature; } public Bytes32 hash_tree_root() { return HashTreeUtil.merkleize( Arrays.asList( - HashTreeUtil.hash_tree_root(SSZTypes.BASIC, SSZ.encodeUInt64(amount.longValue())), - HashTreeUtil.hash_tree_root(SSZTypes.BASIC, SSZ.encodeUInt64(timestamp.longValue())), - deposit_input.hash_tree_root())); - } + HashTreeUtil.hash_tree_root(SSZTypes.TUPLE_OF_BASIC, pubkey.toBytes()), + HashTreeUtil.hash_tree_root(SSZTypes.TUPLE_OF_BASIC, withdrawal_credentials), + HashTreeUtil.hash_tree_root(SSZTypes.BASIC, SSZ.encodeUInt64(amount.longValue())), + HashTreeUtil.hash_tree_root(SSZTypes.TUPLE_OF_BASIC, signature.toBytes()))); } } diff --git a/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/operations/IndexedAttestation.java b/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/operations/IndexedAttestation.java new file mode 100644 index 00000000000..d0f99803414 --- /dev/null +++ b/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/operations/IndexedAttestation.java @@ -0,0 +1,161 @@ +/* + * Copyright 2019 ConsenSys AG. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.artemis.datastructures.operations; + +import com.google.common.primitives.UnsignedLong; +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; +import org.apache.tuweni.ssz.SSZ; +import tech.pegasys.artemis.util.bls.BLSSignature; +import tech.pegasys.artemis.util.hashtree.HashTreeUtil; +import tech.pegasys.artemis.util.hashtree.HashTreeUtil.SSZTypes; +import tech.pegasys.artemis.util.hashtree.Merkleizable; + +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +public class IndexedAttestation implements Merkleizable { + + private List custody_bit_0_indices; + private List custody_bit_1_indices; + private AttestationData data; + private BLSSignature signature; + + public IndexedAttestation( + List custody_bit_0_indices, + List custody_bit_1_indices, + AttestationData data, + BLSSignature signature) { + this.custody_bit_0_indices = custody_bit_0_indices; + this.custody_bit_1_indices = custody_bit_1_indices; + this.data = data; + this.signature = signature; + } + + public IndexedAttestation(IndexedAttestation indexedAttestation) { + this.custody_bit_0_indices = indexedAttestation.getCustody_bit_0_indices().stream().collect(Collectors.toList()); + this.custody_bit_1_indices = indexedAttestation.getCustody_bit_1_indices().stream().collect(Collectors.toList()); + this.data = new AttestationData(data); + this.signature = new BLSSignature(indexedAttestation.getSignature().getSignature()); + } + + public static IndexedAttestation fromBytes(Bytes bytes) { + return SSZ.decode( + bytes, + reader -> + new IndexedAttestation( + reader.readUInt64List().stream() + .map(UnsignedLong::fromLongBits) + .collect(Collectors.toList()), + reader.readUInt64List().stream() + .map(UnsignedLong::fromLongBits) + .collect(Collectors.toList()), + AttestationData.fromBytes(reader.readBytes()), + BLSSignature.fromBytes(reader.readBytes()))); + } + + public Bytes toBytes() { + return SSZ.encode( + writer -> { + writer.writeULongIntList( + 64, + custody_bit_0_indices.stream().map(UnsignedLong::longValue).collect(Collectors.toList())); + writer.writeULongIntList( + 64, + custody_bit_1_indices.stream().map(UnsignedLong::longValue).collect(Collectors.toList())); + writer.writeBytes(data.toBytes()); + writer.writeBytes(signature.toBytes()); + }); + } + + @Override + public int hashCode() { + return Objects.hash(custody_bit_0_indices, custody_bit_1_indices, data, signature); + } + + @Override + public boolean equals(Object obj) { + if (Objects.isNull(obj)) { + return false; + } + + if (this == obj) { + return true; + } + + if (!(obj instanceof IndexedAttestation)) { + return false; + } + + IndexedAttestation other = (IndexedAttestation) obj; + return Objects.equals(this.getCustody_bit_0_indices(), other.getCustody_bit_0_indices()) + && Objects.equals(this.getCustody_bit_1_indices(), other.getCustody_bit_1_indices()) + && Objects.equals(this.getData(), other.getData()) + && Objects.equals(this.getSignature(), other.getSignature()); + } + + /** ******************* * GETTERS & SETTERS * * ******************* */ + + public List getCustody_bit_0_indices() { + return custody_bit_0_indices; + } + + public void setCustody_bit_0_indices(List custody_bit_0_indices) { + this.custody_bit_0_indices = custody_bit_0_indices; + } + + public List getCustody_bit_1_indices() { + return custody_bit_1_indices; + } + + public void setCustody_bit_1_indices(List custody_bit_1_indices) { + this.custody_bit_1_indices = custody_bit_1_indices; + } + + public AttestationData getData() { + return data; + } + + public void setData(AttestationData data) { + this.data = data; + } + + public BLSSignature getSignature() { + return signature; + } + + public void setSignature(BLSSignature signature) { + this.signature = signature; + } + + @Override + public Bytes32 hash_tree_root() { + return HashTreeUtil.merkleize( + Arrays.asList( + HashTreeUtil.hash_tree_root( + SSZTypes.LIST_OF_BASIC, + custody_bit_0_indices.stream() + .map(item -> SSZ.encodeUInt64(item.longValue())) + .collect(Collectors.toList())), + HashTreeUtil.hash_tree_root( + SSZTypes.LIST_OF_BASIC, + custody_bit_1_indices.stream() + .map(item -> SSZ.encodeUInt64(item.longValue())) + .collect(Collectors.toList())), + data.hash_tree_root(), + HashTreeUtil.hash_tree_root(SSZTypes.TUPLE_OF_BASIC, signature.toBytes()))); + } +} diff --git a/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/state/BeaconState.java b/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/state/BeaconState.java index d95cc2e14c9..7a09b6403d6 100644 --- a/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/state/BeaconState.java +++ b/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/state/BeaconState.java @@ -42,17 +42,11 @@ public class BeaconState { // Validator registry protected List validator_registry; - protected List validator_balances; - protected UnsignedLong validator_registry_update_epoch; + protected List balances; // Randomness and committees protected List latest_randao_mixes; // Bounded by LATEST_RANDAO_MIXES_LENGTH - protected UnsignedLong previous_shuffling_start_shard; - protected UnsignedLong current_shuffling_start_shard; - protected UnsignedLong previous_shuffling_epoch; - protected UnsignedLong current_shuffling_epoch; - protected Bytes32 previous_shuffling_seed; - protected Bytes32 current_shuffling_seed; + protected UnsignedLong latest_start_shard; // Finality protected List previous_epoch_attestations; @@ -66,7 +60,10 @@ public class BeaconState { protected Bytes32 finalized_root; // Recent state - protected List latest_crosslinks; // Bounded by SHARD_COUNT + protected List current_crosslinks; // Bounded by SHARD_COUNT + + + protected List previous_crosslinks; // Bounded by SHARD_COUNT protected List latest_block_roots; // Bounded by SLOTS_PER_HISTORICAL_ROOT protected List latest_state_roots; // Bounded by SLOTS_PER_HISTORICAL_ROOT protected List latest_active_index_roots; // Bounded by LATEST_ACTIVE_INDEX_ROOTS_LENGTH @@ -93,18 +90,12 @@ public BeaconState() { UnsignedLong.valueOf(Constants.GENESIS_EPOCH)); this.validator_registry = new ArrayList<>(); - this.validator_balances = new ArrayList<>(); - this.validator_registry_update_epoch = UnsignedLong.valueOf(Constants.GENESIS_EPOCH); + this.balances = new ArrayList<>(); this.latest_randao_mixes = new ArrayList<>( Collections.nCopies(Constants.LATEST_RANDAO_MIXES_LENGTH, Constants.ZERO_HASH)); - this.previous_shuffling_start_shard = UnsignedLong.valueOf(Constants.GENESIS_START_SHARD); - this.current_shuffling_start_shard = UnsignedLong.valueOf(Constants.GENESIS_START_SHARD); - this.previous_shuffling_epoch = UnsignedLong.valueOf(Constants.GENESIS_EPOCH); - this.current_shuffling_epoch = UnsignedLong.valueOf(Constants.GENESIS_EPOCH); - this.previous_shuffling_seed = ZERO_HASH; - this.current_shuffling_seed = ZERO_HASH; + this.latest_start_shard = UnsignedLong.ZERO; // TODO: not sure about this this.previous_epoch_attestations = new ArrayList<>(); this.current_epoch_attestations = new ArrayList<>(); @@ -116,7 +107,8 @@ public BeaconState() { this.finalized_epoch = UnsignedLong.valueOf(Constants.GENESIS_EPOCH); this.finalized_root = Constants.ZERO_HASH; - this.latest_crosslinks = new ArrayList<>(Constants.SHARD_COUNT); + this.current_crosslinks = new ArrayList<>(Constants.SHARD_COUNT); + this.previous_crosslinks = new ArrayList<>(Constants.SHARD_COUNT); this.latest_block_roots = new ArrayList<>( Collections.nCopies(Constants.SLOTS_PER_HISTORICAL_ROOT, Constants.ZERO_HASH)); @@ -133,13 +125,9 @@ public BeaconState() { BeaconBlockUtil.get_temporary_block_header(BeaconBlockUtil.get_empty_block()); this.historical_roots = new ArrayList<>(); - this.latest_eth1_data = new Eth1Data(ZERO_HASH, ZERO_HASH); + this.latest_eth1_data = new Eth1Data(ZERO_HASH, UnsignedLong.ZERO, ZERO_HASH); this.eth1_data_votes = new ArrayList<>(); this.deposit_index = UnsignedLong.ZERO; - for (int i = 0; i < Constants.SHARD_COUNT; i++) { - this.latest_crosslinks.add( - new Crosslink(UnsignedLong.valueOf(Constants.GENESIS_SLOT), Bytes32.ZERO)); - } } public BeaconState( @@ -150,17 +138,11 @@ public BeaconState( // Validator registry List validator_registry, - List validator_balances, - UnsignedLong validator_registry_update_epoch, + List balances, // Randomness and committees List latest_randao_mixes, - UnsignedLong previous_shuffling_start_shard, - UnsignedLong current_shuffling_start_shard, - UnsignedLong previous_shuffling_epoch, - UnsignedLong current_shuffling_epoch, - Bytes32 previous_shuffling_seed, - Bytes32 current_shuffling_seed, + UnsignedLong latest_start_shard, // Finality List previous_epoch_attestations, @@ -174,7 +156,8 @@ public BeaconState( Bytes32 finalized_root, // Recent state - List latest_crosslinks, + List current_crosslinks, + List previous_crosslinks, List latest_block_roots, List latest_state_roots, List latest_active_index_roots, @@ -187,20 +170,13 @@ public BeaconState( List eth1_data_votes, UnsignedLong deposit_index) { this.slot = slot; - this.genesis_time = genesis_time; this.fork = fork; + this.genesis_time = genesis_time; this.validator_registry = validator_registry; - this.validator_balances = validator_balances; - this.validator_registry_update_epoch = validator_registry_update_epoch; + this.balances = balances; this.latest_randao_mixes = latest_randao_mixes; - this.previous_shuffling_start_shard = previous_shuffling_start_shard; - this.current_shuffling_start_shard = current_shuffling_start_shard; - this.previous_shuffling_epoch = previous_shuffling_epoch; - this.current_shuffling_epoch = current_shuffling_epoch; - this.previous_shuffling_seed = previous_shuffling_seed; - this.current_shuffling_seed = current_shuffling_seed; this.previous_epoch_attestations = previous_epoch_attestations; this.current_epoch_attestations = current_epoch_attestations; @@ -212,7 +188,8 @@ public BeaconState( this.finalized_epoch = finalized_epoch; this.finalized_root = finalized_root; - this.latest_crosslinks = latest_crosslinks; + this.current_crosslinks = current_crosslinks; + this.previous_crosslinks = previous_crosslinks; this.latest_block_roots = latest_block_roots; this.latest_state_roots = latest_state_roots; this.latest_active_index_roots = latest_active_index_roots; @@ -233,7 +210,7 @@ public static BeaconState fromBytes(Bytes bytes) { // Misc UnsignedLong.fromLongBits(reader.readUInt64()), UnsignedLong.fromLongBits(reader.readUInt64()), - Fork.fromBytes(reader.readBytes()), + Fork.fromBytes(reader.readBytes()), // Validator registry reader.readBytesList().stream() .map(Validator::fromBytes) @@ -241,17 +218,11 @@ public static BeaconState fromBytes(Bytes bytes) { reader.readUInt64List().stream() .map(UnsignedLong::fromLongBits) .collect(Collectors.toList()), - UnsignedLong.fromLongBits(reader.readUInt64()), // Randomness and committees reader.readFixedBytesList((long) Constants.LATEST_RANDAO_MIXES_LENGTH, 32).stream() .map(Bytes32::wrap) .collect(Collectors.toList()), UnsignedLong.fromLongBits(reader.readUInt64()), - UnsignedLong.fromLongBits(reader.readUInt64()), - UnsignedLong.fromLongBits(reader.readUInt64()), - UnsignedLong.fromLongBits(reader.readUInt64()), - Bytes32.wrap(reader.readFixedBytes(32)), - Bytes32.wrap(reader.readFixedBytes(32)), // Finality reader.readBytesList().stream() .map(PendingAttestation::fromBytes) @@ -270,6 +241,9 @@ public static BeaconState fromBytes(Bytes bytes) { reader.readBytesList((long) Constants.SHARD_COUNT).stream() .map(Crosslink::fromBytes) .collect(Collectors.toList()), + reader.readBytesList((long) Constants.SHARD_COUNT).stream() + .map(Crosslink::fromBytes) + .collect(Collectors.toList()), reader.readFixedBytesList((long) Constants.SLOTS_PER_HISTORICAL_ROOT, 32).stream() .map(Bytes32::wrap) .collect(Collectors.toList()), @@ -282,7 +256,7 @@ public static BeaconState fromBytes(Bytes bytes) { .collect(Collectors.toList()), reader.readUInt64List().stream() .map(UnsignedLong::fromLongBits) - .collect(Collectors.toList()), + .collect(Collectors.toList()), // TODO This must be a fixed sized list BeaconBlockHeader.fromBytes(reader.readBytes()), reader.readFixedBytesList(32).stream() .map(Bytes32::wrap) @@ -298,8 +272,10 @@ public static BeaconState fromBytes(Bytes bytes) { public Bytes toBytes() { List validator_registryBytes = validator_registry.stream().map(item -> item.toBytes()).collect(Collectors.toList()); - List latest_crosslinksBytes = - latest_crosslinks.stream().map(item -> item.toBytes()).collect(Collectors.toList()); + List current_crosslinksBytes = + current_crosslinks.stream().map(item -> item.toBytes()).collect(Collectors.toList()); + List previous_crosslinksBytes = + previous_crosslinks.stream().map(item -> item.toBytes()).collect(Collectors.toList()); List eth1_data_votesBytes = eth1_data_votes.stream().map(item -> item.toBytes()).collect(Collectors.toList()); List previous_epoch_attestationsBytes = @@ -321,19 +297,13 @@ public Bytes toBytes() { writer.writeBytesList(validator_registryBytes); writer.writeULongIntList( 64, - validator_balances.stream() + balances.stream() .map(UnsignedLong::longValue) .collect(Collectors.toList())); - writer.writeUInt64(validator_registry_update_epoch.longValue()); // Randomness and committees writer.writeFixedBytesList( (long) Constants.LATEST_RANDAO_MIXES_LENGTH, 32, latest_randao_mixes); - writer.writeUInt64(previous_shuffling_start_shard.longValue()); - writer.writeUInt64(current_shuffling_start_shard.longValue()); - writer.writeUInt64(previous_shuffling_epoch.longValue()); - writer.writeUInt64(current_shuffling_epoch.longValue()); - writer.writeFixedBytes(32, previous_shuffling_seed); - writer.writeFixedBytes(32, current_shuffling_seed); + writer.writeUInt64(latest_start_shard.longValue()); // Finality writer.writeBytesList(previous_epoch_attestationsBytes); writer.writeBytesList(current_epoch_attestationsBytes); @@ -345,7 +315,8 @@ public Bytes toBytes() { writer.writeUInt64(finalized_epoch.longValue()); writer.writeFixedBytes(32, finalized_root); // Recent state - writer.writeBytesList((long) Constants.SHARD_COUNT, latest_crosslinksBytes); + writer.writeBytesList((long) Constants.SHARD_COUNT, current_crosslinksBytes); + writer.writeBytesList((long) Constants.SHARD_COUNT, previous_crosslinksBytes); writer.writeFixedBytesList( (long) Constants.SLOTS_PER_HISTORICAL_ROOT, 32, latest_block_roots); writer.writeFixedBytesList( @@ -373,15 +344,9 @@ public int hashCode() { genesis_time, fork, validator_registry, - validator_balances, - validator_registry_update_epoch, + balances, latest_randao_mixes, - previous_shuffling_start_shard, - current_shuffling_start_shard, - previous_shuffling_epoch, - current_shuffling_epoch, - previous_shuffling_seed, - current_shuffling_seed, + latest_start_shard, previous_epoch_attestations, current_epoch_attestations, previous_justified_epoch, @@ -391,7 +356,8 @@ public int hashCode() { justification_bitfield, finalized_epoch, finalized_root, - latest_crosslinks, + current_crosslinks, + previous_crosslinks, latest_block_roots, latest_state_roots, latest_active_index_roots, @@ -422,18 +388,9 @@ public boolean equals(Object obj) { && Objects.equals(this.getGenesis_time(), other.getGenesis_time()) && Objects.equals(this.getFork(), other.getFork()) && Objects.equals(this.getValidator_registry(), other.getValidator_registry()) - && Objects.equals(this.getValidator_balances(), other.getValidator_balances()) - && Objects.equals( - this.getValidator_registry_update_epoch(), other.getValidator_registry_update_epoch()) + && Objects.equals(this.getBalances(), other.getBalances()) && Objects.equals(this.getLatest_randao_mixes(), other.getLatest_randao_mixes()) - && Objects.equals( - this.getPrevious_shuffling_start_shard(), other.getPrevious_shuffling_start_shard()) - && Objects.equals( - this.getCurrent_shuffling_start_shard(), other.getCurrent_shuffling_start_shard()) - && Objects.equals(this.getPrevious_shuffling_epoch(), other.getPrevious_shuffling_epoch()) - && Objects.equals(this.getCurrent_shuffling_epoch(), other.getCurrent_shuffling_epoch()) - && Objects.equals(this.getPrevious_shuffling_seed(), other.getPrevious_shuffling_seed()) - && Objects.equals(this.getCurrent_shuffling_seed(), other.getCurrent_shuffling_seed()) + && Objects.equals(this.getLatest_start_shard(), other.getLatest_start_shard()) && Objects.equals( this.getPrevious_epoch_attestations(), other.getPrevious_epoch_attestations()) && Objects.equals( @@ -445,7 +402,8 @@ public boolean equals(Object obj) { && Objects.equals(this.getJustification_bitfield(), other.getJustification_bitfield()) && Objects.equals(this.getFinalized_epoch(), other.getFinalized_epoch()) && Objects.equals(this.getFinalized_root(), other.getFinalized_root()) - && Objects.equals(this.getLatest_crosslinks(), other.getLatest_crosslinks()) + && Objects.equals(this.getCurrent_crosslinks(), other.getCurrent_crosslinks()) + && Objects.equals(this.getPrevious_crosslinks(), other.getPrevious_crosslinks()) && Objects.equals(this.getLatest_block_roots(), other.getLatest_block_roots()) && Objects.equals(this.getLatest_state_roots(), other.getLatest_state_roots()) && Objects.equals(this.getLatest_active_index_roots(), other.getLatest_active_index_roots()) @@ -490,20 +448,12 @@ public void setValidator_registry(List validator_registry) { this.validator_registry = validator_registry; } - public List getValidator_balances() { - return validator_balances; - } - - public void setValidator_balances(List validator_balances) { - this.validator_balances = validator_balances; - } - - public UnsignedLong getValidator_registry_update_epoch() { - return validator_registry_update_epoch; + public List getBalances() { + return balances; } - public void setValidator_registry_update_epoch(UnsignedLong validator_registry_update_epoch) { - this.validator_registry_update_epoch = validator_registry_update_epoch; + public void setBalances(List balances) { + this.balances = balances; } public List getLatest_randao_mixes() { @@ -514,52 +464,12 @@ public void setLatest_randao_mixes(List latest_randao_mixes) { this.latest_randao_mixes = latest_randao_mixes; } - public UnsignedLong getPrevious_shuffling_start_shard() { - return previous_shuffling_start_shard; - } - - public void setPrevious_shuffling_start_shard(UnsignedLong previous_shuffling_start_shard) { - this.previous_shuffling_start_shard = previous_shuffling_start_shard; - } - - public UnsignedLong getCurrent_shuffling_start_shard() { - return current_shuffling_start_shard; - } - - public void setCurrent_shuffling_start_shard(UnsignedLong current_shuffling_start_shard) { - this.current_shuffling_start_shard = current_shuffling_start_shard; + public UnsignedLong getLatest_start_shard() { + return latest_start_shard; } - public UnsignedLong getPrevious_shuffling_epoch() { - return previous_shuffling_epoch; - } - - public void setPrevious_shuffling_epoch(UnsignedLong previous_shuffling_epoch) { - this.previous_shuffling_epoch = previous_shuffling_epoch; - } - - public UnsignedLong getCurrent_shuffling_epoch() { - return current_shuffling_epoch; - } - - public void setCurrent_shuffling_epoch(UnsignedLong current_shuffling_epoch) { - this.current_shuffling_epoch = current_shuffling_epoch; - } - - public Bytes32 getPrevious_shuffling_seed() { - return previous_shuffling_seed; - } - - public void setPrevious_shuffling_seed(Bytes32 previous_shuffling_seed) { - this.previous_shuffling_seed = previous_shuffling_seed; - } - - public Bytes32 getCurrent_shuffling_seed() { - return current_shuffling_seed; - } - - public void setCurrent_shuffling_seed(Bytes32 current_shuffling_seed) { - this.current_shuffling_seed = current_shuffling_seed; + public void setLatest_start_shard(UnsignedLong latest_start_shard) { + this.latest_start_shard = latest_start_shard; } public List getPrevious_epoch_attestations() { @@ -634,12 +544,20 @@ public void setFinalized_root(Bytes32 finalized_root) { this.finalized_root = finalized_root; } - public List getLatest_crosslinks() { - return latest_crosslinks; + public List getCurrent_crosslinks() { + return current_crosslinks; + } + + public void setCurrent_crosslinks(ArrayList current_crosslinks) { + this.current_crosslinks = current_crosslinks; } - public void setLatest_crosslinks(ArrayList latest_crosslinks) { - this.latest_crosslinks = latest_crosslinks; + public List getPrevious_crosslinks() { + return previous_crosslinks; + } + + public void setPrevious_crosslinks(List previous_crosslinks) { + this.previous_crosslinks = previous_crosslinks; } public List getLatest_block_roots() { @@ -714,6 +632,7 @@ public void setDeposit_index(UnsignedLong deposit_index) { this.deposit_index = deposit_index; } + public void incrementSlot() { this.slot = slot.plus(UnsignedLong.ONE); } @@ -729,23 +648,12 @@ public Bytes32 hash_tree_root() { HashTreeUtil.hash_tree_root(SSZTypes.LIST_OF_COMPOSITE, validator_registry), HashTreeUtil.hash_tree_root( SSZTypes.LIST_OF_BASIC, - validator_balances.stream() + balances.stream() .map(item -> SSZ.encodeUInt64(item.longValue())) .collect(Collectors.toList())), - HashTreeUtil.hash_tree_root( - SSZTypes.BASIC, SSZ.encodeUInt64(validator_registry_update_epoch.longValue())), // Randomness and committees HashTreeUtil.hash_tree_root(SSZTypes.TUPLE_OF_COMPOSITE, latest_randao_mixes), - HashTreeUtil.hash_tree_root( - SSZTypes.BASIC, SSZ.encodeUInt64(previous_shuffling_start_shard.longValue())), - HashTreeUtil.hash_tree_root( - SSZTypes.BASIC, SSZ.encodeUInt64(current_shuffling_start_shard.longValue())), - HashTreeUtil.hash_tree_root( - SSZTypes.BASIC, SSZ.encodeUInt64(previous_shuffling_epoch.longValue())), - HashTreeUtil.hash_tree_root( - SSZTypes.BASIC, SSZ.encodeUInt64(current_shuffling_epoch.longValue())), - HashTreeUtil.hash_tree_root(SSZTypes.TUPLE_OF_BASIC, previous_shuffling_seed), - HashTreeUtil.hash_tree_root(SSZTypes.TUPLE_OF_BASIC, current_shuffling_seed), + HashTreeUtil.hash_tree_root(SSZTypes.BASIC, SSZ.encodeUInt64(latest_start_shard.longValue())), // Finality HashTreeUtil.hash_tree_root(SSZTypes.LIST_OF_COMPOSITE, previous_epoch_attestations), HashTreeUtil.hash_tree_root(SSZTypes.LIST_OF_COMPOSITE, current_epoch_attestations), @@ -762,9 +670,13 @@ public Bytes32 hash_tree_root() { HashTreeUtil.hash_tree_root(SSZTypes.TUPLE_OF_BASIC, finalized_root), // Recent state HashTreeUtil.merkleize( - latest_crosslinks.stream() + current_crosslinks.stream() .map(item -> item.hash_tree_root()) .collect(Collectors.toList())), + HashTreeUtil.merkleize( + previous_crosslinks.stream() + .map(item -> item.hash_tree_root()) + .collect(Collectors.toList())), HashTreeUtil.hash_tree_root(SSZTypes.TUPLE_OF_COMPOSITE, latest_block_roots), HashTreeUtil.hash_tree_root(SSZTypes.TUPLE_OF_COMPOSITE, latest_state_roots), HashTreeUtil.hash_tree_root(SSZTypes.TUPLE_OF_COMPOSITE, latest_active_index_roots), diff --git a/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/state/BeaconStateWithCache.java b/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/state/BeaconStateWithCache.java index 1e6567133f0..80759b1a933 100644 --- a/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/state/BeaconStateWithCache.java +++ b/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/state/BeaconStateWithCache.java @@ -42,17 +42,11 @@ public BeaconStateWithCache(BeaconStateWithCache state) { this.fork = new Fork(state.getFork()); this.validator_registry = this.copyList(state.getValidator_registry(), new ArrayList<>()); - this.validator_balances = state.getValidator_balances().stream().collect(Collectors.toList()); - this.validator_registry_update_epoch = state.getValidator_registry_update_epoch(); + this.balances = state.getBalances().stream().collect(Collectors.toList()); this.latest_randao_mixes = this.copyBytesList(state.getLatest_randao_mixes(), new ArrayList<>()); - this.previous_shuffling_start_shard = state.getPrevious_shuffling_start_shard(); - this.current_shuffling_start_shard = state.getCurrent_shuffling_start_shard(); - this.previous_shuffling_epoch = state.getPrevious_shuffling_epoch(); - this.current_shuffling_epoch = state.getCurrent_shuffling_epoch(); - this.previous_shuffling_seed = state.getPrevious_shuffling_seed(); - this.current_shuffling_seed = state.getCurrent_shuffling_seed(); + this.latest_start_shard = state.getLatest_start_shard(); this.previous_epoch_attestations = this.copyList(state.getPrevious_epoch_attestations(), new ArrayList<>()); @@ -66,7 +60,8 @@ public BeaconStateWithCache(BeaconStateWithCache state) { this.finalized_epoch = state.getFinalized_epoch(); this.finalized_root = state.getFinalized_root(); - this.latest_crosslinks = this.copyList(state.getLatest_crosslinks(), new ArrayList<>()); + this.current_crosslinks = this.copyList(state.getCurrent_crosslinks(), new ArrayList<>()); + this.previous_crosslinks = this.copyList(state.getPrevious_crosslinks(), new ArrayList<>()); this.latest_block_roots = this.copyBytesList(state.getLatest_block_roots(), new ArrayList<>()); this.latest_state_roots = this.copyBytesList(state.getLatest_state_roots(), new ArrayList<>()); this.latest_active_index_roots = diff --git a/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/state/Crosslink.java b/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/state/Crosslink.java index aad815c6b64..e9c43e7d5a9 100644 --- a/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/state/Crosslink.java +++ b/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/state/Crosslink.java @@ -25,17 +25,26 @@ public class Crosslink implements Copyable { - private UnsignedLong epoch; - private Bytes32 crosslink_data_root; - - public Crosslink(UnsignedLong epoch, Bytes32 crosslink_data_root) { - this.epoch = epoch; - this.crosslink_data_root = crosslink_data_root; + private UnsignedLong shard; + private UnsignedLong start_epoch; + private UnsignedLong end_epoch; + private Bytes32 parent_root; + private Bytes32 data_root; + + public Crosslink(UnsignedLong shard, UnsignedLong start_epoch, UnsignedLong end_epoch, Bytes32 parent_root, Bytes32 data_root) { + this.shard = shard; + this.start_epoch = start_epoch; + this.end_epoch = end_epoch; + this.parent_root = parent_root; + this.data_root = data_root; } public Crosslink(Crosslink crosslink) { - this.epoch = crosslink.getEpoch(); - this.crosslink_data_root = crosslink.getCrosslink_data_root().copy(); + this.shard = crosslink.getShard(); + this.start_epoch = crosslink.getStart_epoch(); + this.end_epoch = crosslink.getEnd_epoch(); + this.parent_root = crosslink.getParent_root(); + this.data_root = crosslink.getData_root(); } public static Crosslink fromBytes(Bytes bytes) { @@ -44,6 +53,9 @@ public static Crosslink fromBytes(Bytes bytes) { reader -> new Crosslink( UnsignedLong.fromLongBits(reader.readUInt64()), + UnsignedLong.fromLongBits(reader.readUInt64()), + UnsignedLong.fromLongBits(reader.readUInt64()), + Bytes32.wrap(reader.readFixedBytes(32)), Bytes32.wrap(reader.readFixedBytes(32)))); } @@ -55,14 +67,17 @@ public Crosslink copy() { public Bytes toBytes() { return SSZ.encode( writer -> { - writer.writeUInt64(epoch.longValue()); - writer.writeFixedBytes(32, crosslink_data_root); + writer.writeUInt64(shard.longValue()); + writer.writeUInt64(start_epoch.longValue()); + writer.writeUInt64(end_epoch.longValue()); + writer.writeFixedBytes(32, parent_root); + writer.writeFixedBytes(32, data_root); }); } @Override public int hashCode() { - return Objects.hash(epoch, crosslink_data_root); + return Objects.hash(shard, start_epoch, end_epoch, parent_root, data_root); } @Override @@ -80,31 +95,61 @@ public boolean equals(Object obj) { } Crosslink other = (Crosslink) obj; - return Objects.equals(this.getEpoch(), other.getEpoch()) - && Objects.equals(this.getCrosslink_data_root(), other.getCrosslink_data_root()); + return Objects.equals(this.getShard(), other.getShard()) + && Objects.equals(this.getStart_epoch(), other.getStart_epoch()) + && Objects.equals(this.getEnd_epoch(), other.getEnd_epoch()) + && Objects.equals(this.getParent_root(), other.getParent_root()) + && Objects.equals(this.getData_root(), other.getData_root()); } /** ******************* * GETTERS & SETTERS * * ******************* */ - public Bytes32 getCrosslink_data_root() { - return crosslink_data_root; + + public UnsignedLong getShard() { + return shard; + } + + public void setShard(UnsignedLong shard) { + this.shard = shard; + } + + public UnsignedLong getStart_epoch() { + return start_epoch; + } + + public void setStart_epoch(UnsignedLong start_epoch) { + this.start_epoch = start_epoch; + } + public UnsignedLong getEnd_epoch() { + return end_epoch; + } + + public void setEnd_epoch(UnsignedLong end_epoch) { + this.end_epoch = end_epoch; + } + + public Bytes32 getParent_root() { + return parent_root; } - public void setCrosslink_data_root(Bytes32 shard_block_root) { - this.crosslink_data_root = shard_block_root; + public void setParent_root(Bytes32 parent_root) { + this.parent_root = parent_root; } - public UnsignedLong getEpoch() { - return epoch; + public Bytes32 getData_root() { + return data_root; } - public void setEpoch(UnsignedLong epoch) { - this.epoch = epoch; + public void setData_root(Bytes32 data_root) { + this.data_root = data_root; } public Bytes32 hash_tree_root() { return HashTreeUtil.merkleize( Arrays.asList( - HashTreeUtil.hash_tree_root(SSZTypes.BASIC, SSZ.encodeUInt64(epoch.longValue())), - HashTreeUtil.hash_tree_root(SSZTypes.TUPLE_OF_BASIC, crosslink_data_root))); + HashTreeUtil.hash_tree_root(SSZTypes.BASIC, SSZ.encodeUInt64(shard.longValue())), + HashTreeUtil.hash_tree_root(SSZTypes.BASIC, SSZ.encodeUInt64(start_epoch.longValue())), + HashTreeUtil.hash_tree_root(SSZTypes.BASIC, SSZ.encodeUInt64(end_epoch.longValue())), + HashTreeUtil.hash_tree_root(SSZTypes.TUPLE_OF_BASIC, parent_root), + HashTreeUtil.hash_tree_root(SSZTypes.TUPLE_OF_BASIC, data_root))); } } diff --git a/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/state/PendingAttestation.java b/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/state/PendingAttestation.java index f334a2d1fcc..b9271673e52 100644 --- a/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/state/PendingAttestation.java +++ b/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/state/PendingAttestation.java @@ -29,25 +29,25 @@ public class PendingAttestation implements Copyable, Merklei private Bytes aggregation_bitfield; private AttestationData data; - private Bytes custody_bitfield; - private UnsignedLong inclusion_slot; + private UnsignedLong inclusion_delay; + private UnsignedLong proposer_index; public PendingAttestation( Bytes aggregation_bitfield, AttestationData data, - Bytes custody_bitfield, - UnsignedLong inclusion_slot) { + UnsignedLong inclusion_delay, + UnsignedLong proposer_index) { this.aggregation_bitfield = aggregation_bitfield; this.data = data; - this.custody_bitfield = custody_bitfield; - this.inclusion_slot = inclusion_slot; + this.inclusion_delay = inclusion_delay; + this.proposer_index = proposer_index; } public PendingAttestation(PendingAttestation pendingAttestation) { this.aggregation_bitfield = pendingAttestation.getAggregation_bitfield().copy(); this.data = new AttestationData(pendingAttestation.getData()); - this.custody_bitfield = pendingAttestation.getCustody_bitfield().copy(); - this.inclusion_slot = pendingAttestation.getInclusion_slot(); + this.inclusion_delay = pendingAttestation.getInclusion_delay(); + this.proposer_index = pendingAttestation.getProposer_index(); } @Override @@ -62,7 +62,7 @@ public static PendingAttestation fromBytes(Bytes bytes) { new PendingAttestation( Bytes.wrap(reader.readBytes()), AttestationData.fromBytes(reader.readBytes()), - Bytes.wrap(reader.readBytes()), + UnsignedLong.fromLongBits(reader.readUInt64()), UnsignedLong.fromLongBits(reader.readUInt64()))); } @@ -71,14 +71,14 @@ public Bytes toBytes() { writer -> { writer.writeBytes(aggregation_bitfield); writer.writeBytes(data.toBytes()); - writer.writeBytes(custody_bitfield); - writer.writeUInt64(inclusion_slot.longValue()); + writer.writeUInt64(inclusion_delay.longValue()); + writer.writeUInt64(proposer_index.longValue()); }); } @Override public int hashCode() { - return Objects.hash(aggregation_bitfield, data, custody_bitfield, inclusion_slot); + return Objects.hash(aggregation_bitfield, data, inclusion_delay, proposer_index); } @Override @@ -97,9 +97,9 @@ public boolean equals(Object obj) { PendingAttestation other = (PendingAttestation) obj; return Objects.equals(this.getAggregation_bitfield(), other.getAggregation_bitfield()) - && Objects.equals(this.getData(), other.getData()) - && Objects.equals(this.getCustody_bitfield(), other.getCustody_bitfield()) - && Objects.equals(this.getInclusion_slot(), other.getInclusion_slot()); + && Objects.equals(this.getData(), other.getData()) + && Objects.equals(this.getInclusion_delay(), other.getInclusion_delay()) + && Objects.equals(this.getProposer_index(), other.getProposer_index()); } /** ******************* * GETTERS & SETTERS * * ******************* */ @@ -119,20 +119,20 @@ public void setData(AttestationData data) { this.data = data; } - public Bytes getCustody_bitfield() { - return custody_bitfield; + public UnsignedLong getInclusion_delay() { + return inclusion_delay; } - public void setCustody_bitfield(Bytes custody_bitfield) { - this.custody_bitfield = custody_bitfield; + public void setInclusion_delay(UnsignedLong inclusion_delay) { + this.inclusion_delay = inclusion_delay; } - public UnsignedLong getInclusion_slot() { - return inclusion_slot; + public UnsignedLong getProposer_index() { + return proposer_index; } - public void setInclusionSlot(UnsignedLong inclusion_slot) { - this.inclusion_slot = inclusion_slot; + public void setProposer_index(UnsignedLong proposer_index) { + this.proposer_index = proposer_index; } @Override @@ -141,8 +141,9 @@ public Bytes32 hash_tree_root() { Arrays.asList( HashTreeUtil.hash_tree_root(SSZTypes.LIST_OF_BASIC, aggregation_bitfield), data.hash_tree_root(), - HashTreeUtil.hash_tree_root(SSZTypes.LIST_OF_BASIC, custody_bitfield), HashTreeUtil.hash_tree_root( - SSZTypes.BASIC, SSZ.encodeUInt64(inclusion_slot.longValue())))); + SSZTypes.BASIC, SSZ.encodeUInt64(inclusion_delay.longValue())), + HashTreeUtil.hash_tree_root( + SSZTypes.BASIC, SSZ.encodeUInt64(proposer_index.longValue())))); } } diff --git a/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/state/Validator.java b/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/state/Validator.java index 44e26dcb7c9..a1e9a0e7d85 100644 --- a/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/state/Validator.java +++ b/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/state/Validator.java @@ -31,42 +31,47 @@ public class Validator implements Copyable, Merkleizable { private BLSPublicKey pubkey; // Withdrawal credentials private Bytes32 withdrawal_credentials; + // Epoch when became eligible for activation + private UnsignedLong activation_eligibility_epoch; // Epoch when validator activated private UnsignedLong activation_epoch; // Epoch when validator exited private UnsignedLong exit_epoch; // Epoch when validator withdrew private UnsignedLong withdrawable_epoch; - // Did the validator initiate an exit - private boolean initiated_exit; // Was the validator slashed private boolean slashed; + // Effective balance + private UnsignedLong effective_balance; public Validator( BLSPublicKey pubkey, Bytes32 withdrawal_credentials, + UnsignedLong activation_eligibility_epoch, UnsignedLong activation_epoch, UnsignedLong exit_epoch, UnsignedLong withdrawal_epoch, - boolean initiated_exit, - boolean slashed) { + boolean slashed, + UnsignedLong effective_balance) { this.pubkey = pubkey; this.withdrawal_credentials = withdrawal_credentials; + this.activation_eligibility_epoch = activation_eligibility_epoch; this.activation_epoch = activation_epoch; this.exit_epoch = exit_epoch; this.withdrawable_epoch = withdrawal_epoch; - this.initiated_exit = initiated_exit; this.slashed = slashed; + this.effective_balance = effective_balance; } public Validator(Validator validator) { this.pubkey = new BLSPublicKey(validator.getPubkey().getPublicKey()); - this.withdrawal_credentials = validator.getWithdrawal_credentials().copy(); + this.withdrawal_credentials = validator.getWithdrawal_credentials(); + this.activation_eligibility_epoch = validator.getActivation_eligibility_epoch(); this.activation_epoch = validator.getActivation_epoch(); this.exit_epoch = validator.getExit_epoch(); this.withdrawable_epoch = validator.getWithdrawable_epoch(); - this.initiated_exit = validator.hasInitiatedExit(); this.slashed = validator.isSlashed(); + this.effective_balance = validator.getEffective_balance(); } @Override @@ -84,8 +89,9 @@ public static Validator fromBytes(Bytes bytes) { UnsignedLong.fromLongBits(reader.readUInt64()), UnsignedLong.fromLongBits(reader.readUInt64()), UnsignedLong.fromLongBits(reader.readUInt64()), + UnsignedLong.fromLongBits(reader.readUInt64()), reader.readBoolean(), - reader.readBoolean())); + UnsignedLong.fromLongBits(reader.readUInt64()))); } public Bytes toBytes() { @@ -93,11 +99,12 @@ public Bytes toBytes() { writer -> { writer.writeBytes(pubkey.toBytes()); writer.writeFixedBytes(32, withdrawal_credentials); + writer.writeUInt64(activation_eligibility_epoch.longValue()); writer.writeUInt64(activation_epoch.longValue()); writer.writeUInt64(exit_epoch.longValue()); writer.writeUInt64(withdrawable_epoch.longValue()); - writer.writeBoolean(initiated_exit); writer.writeBoolean(slashed); + writer.writeUInt64(effective_balance.longValue()); }); } @@ -106,11 +113,12 @@ public int hashCode() { return Objects.hash( pubkey, withdrawal_credentials, + activation_eligibility_epoch, activation_epoch, exit_epoch, withdrawable_epoch, - initiated_exit, - slashed); + slashed, + effective_balance); } @Override @@ -130,11 +138,12 @@ public boolean equals(Object obj) { Validator other = (Validator) obj; return Objects.equals(this.getPubkey(), other.getPubkey()) && Objects.equals(this.getWithdrawal_credentials(), other.getWithdrawal_credentials()) + && Objects.equals(this.getActivation_eligibility_epoch(), other.getActivation_eligibility_epoch()) && Objects.equals(this.getActivation_epoch(), other.getActivation_epoch()) && Objects.equals(this.getExit_epoch(), other.getExit_epoch()) && Objects.equals(this.getWithdrawable_epoch(), other.getWithdrawable_epoch()) - && Objects.equals(this.hasInitiatedExit(), other.hasInitiatedExit()) - && Objects.equals(this.isSlashed(), other.isSlashed()); + && Objects.equals(this.isSlashed(), other.isSlashed()) + && Objects.equals(this.getEffective_balance(), other.getEffective_balance()); } public BLSPublicKey getPubkey() { @@ -153,6 +162,13 @@ public void setWithdrawal_credentials(Bytes32 withdrawal_credentials) { this.withdrawal_credentials = withdrawal_credentials; } + public UnsignedLong getActivation_eligibility_epoch() { + return activation_eligibility_epoch; + } + + public void setActivation_eligibility_epoch(UnsignedLong activation_eligibility_epoch) { + this.activation_eligibility_epoch = activation_eligibility_epoch; + } public UnsignedLong getActivation_epoch() { return activation_epoch; } @@ -177,14 +193,6 @@ public void setWithdrawable_epoch(UnsignedLong withdrawable_epoch) { this.withdrawable_epoch = withdrawable_epoch; } - public boolean hasInitiatedExit() { - return initiated_exit; - } - - public void setInitiatedExit(boolean initiated_exit) { - this.initiated_exit = initiated_exit; - } - public boolean isSlashed() { return slashed; } @@ -193,18 +201,28 @@ public void setSlashed(boolean slashed) { this.slashed = slashed; } + public UnsignedLong getEffective_balance() { + return effective_balance; + } + + public void setEffective_balance(UnsignedLong effective_balance) { + this.effective_balance = effective_balance; + } + @Override public Bytes32 hash_tree_root() { return HashTreeUtil.merkleize( Arrays.asList( HashTreeUtil.hash_tree_root(SSZTypes.TUPLE_OF_BASIC, pubkey.toBytes()), HashTreeUtil.hash_tree_root(SSZTypes.TUPLE_OF_BASIC, withdrawal_credentials), + HashTreeUtil.hash_tree_root( + SSZTypes.BASIC, SSZ.encodeUInt64(activation_eligibility_epoch.longValue())), HashTreeUtil.hash_tree_root( SSZTypes.BASIC, SSZ.encodeUInt64(activation_epoch.longValue())), HashTreeUtil.hash_tree_root(SSZTypes.BASIC, SSZ.encodeUInt64(exit_epoch.longValue())), HashTreeUtil.hash_tree_root( SSZTypes.BASIC, SSZ.encodeUInt64(withdrawable_epoch.longValue())), - HashTreeUtil.hash_tree_root(SSZTypes.BASIC, SSZ.encodeBoolean(initiated_exit)), - HashTreeUtil.hash_tree_root(SSZTypes.BASIC, SSZ.encodeBoolean(slashed)))); + HashTreeUtil.hash_tree_root(SSZTypes.BASIC, SSZ.encodeBoolean(slashed)), + HashTreeUtil.hash_tree_root(SSZTypes.BASIC, SSZ.encodeUInt64(effective_balance.longValue())))); } } diff --git a/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/util/AttestationUtil.java b/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/util/AttestationUtil.java index 636e42826ed..866a3d75105 100644 --- a/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/util/AttestationUtil.java +++ b/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/util/AttestationUtil.java @@ -14,9 +14,6 @@ package tech.pegasys.artemis.datastructures.util; import com.google.common.primitives.UnsignedLong; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; import org.apache.commons.lang3.tuple.ImmutableTriple; import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Triple; @@ -27,11 +24,41 @@ import tech.pegasys.artemis.datastructures.operations.Attestation; import tech.pegasys.artemis.datastructures.operations.AttestationData; import tech.pegasys.artemis.datastructures.operations.AttestationDataAndCustodyBit; +import tech.pegasys.artemis.datastructures.operations.IndexedAttestation; import tech.pegasys.artemis.datastructures.state.BeaconState; import tech.pegasys.artemis.datastructures.state.Crosslink; import tech.pegasys.artemis.datastructures.state.CrosslinkCommittee; +import tech.pegasys.artemis.datastructures.state.Validator; import tech.pegasys.artemis.util.bls.BLSKeyPair; import tech.pegasys.artemis.util.bls.BLSPublicKey; +import tech.pegasys.artemis.util.bls.BLSSignature; +import tech.pegasys.artemis.util.bls.BLSVerify; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import static com.google.common.base.Preconditions.checkArgument; +import static tech.pegasys.artemis.datastructures.Constants.DOMAIN_ATTESTATION; +import static tech.pegasys.artemis.datastructures.Constants.MAX_INDICES_PER_ATTESTATION; +import static tech.pegasys.artemis.datastructures.Constants.SHARD_COUNT; +import static tech.pegasys.artemis.datastructures.Constants.SLOTS_PER_EPOCH; +import static tech.pegasys.artemis.datastructures.util.BeaconStateUtil.get_bitfield_bit; +import static tech.pegasys.artemis.datastructures.util.BeaconStateUtil.get_domain; +import static tech.pegasys.artemis.datastructures.util.BeaconStateUtil.get_epoch_committee_count; +import static tech.pegasys.artemis.datastructures.util.BeaconStateUtil.get_epoch_start_slot; +import static tech.pegasys.artemis.datastructures.util.BeaconStateUtil.verify_bitfield; +import static tech.pegasys.artemis.datastructures.util.CrosslinkCommitteeUtil.get_crosslink_committee; +import static tech.pegasys.artemis.datastructures.util.CrosslinkCommitteeUtil.get_epoch_committee_count; +import static tech.pegasys.artemis.datastructures.util.CrosslinkCommitteeUtil.get_epoch_start_shard; +import static tech.pegasys.artemis.util.bls.BLSAggregate.bls_aggregate_pubkeys; +import static tech.pegasys.artemis.util.hashtree.HashTreeUtil.SSZTypes.LIST_OF_BASIC; +import static tech.pegasys.artemis.util.hashtree.HashTreeUtil.hash_tree_root; public class AttestationUtil { @@ -80,7 +107,7 @@ public static AttestationData getGenericAttestationData(BeaconState state, Beaco Bytes32 headBlockRoot = block.signed_root("signature"); Bytes32 crosslinkDataRoot = Bytes32.ZERO; UnsignedLong epochStartSlot = - BeaconStateUtil.get_epoch_start_slot(BeaconStateUtil.get_current_epoch(state)); + get_epoch_start_slot(BeaconStateUtil.get_current_epoch(state)); Bytes32 epochBoundaryRoot; if (epochStartSlot.compareTo(slot) == 0) { epochBoundaryRoot = block.signed_root("signature"); @@ -125,8 +152,8 @@ public static AttestationData completeAttestationData( UnsignedLong shard = committee.getShard(); attestationData.setShard(shard); Crosslink previousCrosslink = - state.getLatest_crosslinks().get(shard.intValue() % Constants.SHARD_COUNT); - attestationData.setPrevious_crosslink(previousCrosslink); + state.getLatest_crosslinks().get(shard.intValue() % SHARD_COUNT); + attestationData.setCrosslink(previousCrosslink); return attestationData; } @@ -137,10 +164,150 @@ public static Bytes32 getAttestationMessageToSign(AttestationData attestationDat } public static int getDomain(BeaconState state, AttestationData attestationData) { - return BeaconStateUtil.get_domain( + return get_domain( state.getFork(), BeaconStateUtil.slot_to_epoch(attestationData.getSlot()), Constants.DOMAIN_ATTESTATION) .intValue(); } + + /** + * Check if ``data_1`` and ``data_2`` are slashable according to Casper FFG rules. + * + * @param data_1 + * @param data_2 + * @return + * + * @see https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#is_slashable_attestation_data + */ + public static boolean is_slashable_attestation_data(AttestationData data_1, AttestationData data_2){ + return ( + //case 1: double vote || case 2: surround vote + (!data_1.equals(data_2) && data_1.getTarget_epoch().equals(data_2.getTarget_epoch()) || + (data_1.getSource_epoch().compareTo(data_2.getSource_epoch()) < 0 && + data_2.getTarget_epoch().compareTo(data_1.getTarget_epoch()) < 0)) + ); + } + + /** + * Convert ``attestation`` to (almost) indexed-verifiable form. + * + * @param state + * @param attestation + * @return + * + * @see https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#convert_to_indexed + */ + public static IndexedAttestation convert_to_indexed(BeaconState state, Attestation attestation){ + List attesting_indices = get_attesting_indices(state, attestation.getData(), attestation.getAggregation_bitfield()); + List custody_bit_1_indices = get_attesting_indices(state, attestation.getData(), attestation.getCustody_bitfield()); + + List custody_bit_0_indices = new ArrayList(); + for(int i = 0; i < attesting_indices.size(); i++){ + Integer index = attesting_indices.get(i); + if(!custody_bit_1_indices.contains(index))custody_bit_0_indices.add(index); + } + return new IndexedAttestation( + custody_bit_0_indices, + custody_bit_1_indices, + attestation.getData(), + attestation.getAggregate_signature() + ); + } + + /** + * Return the sorted attesting indices corresponding to ``attestation_data`` and ``bitfield``. + * + * @param state + * @param attestation_data + * @param bitfield + * @return + * @throws IllegalArgumentException + * + * @see https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#get_attesting_indices + */ + public static List get_attesting_indices( + BeaconState state, AttestationData attestation_data, Bytes bitfield) throws IllegalArgumentException { + List committee = get_crosslink_committee(state, attestation_data.getTarget_epoch(), attestation_data.getCrosslink().getShard()); + checkArgument(verify_bitfield(bitfield, committee.size()), "AttestationUtil.get_attesting_indices"); + + List attesting_indices = new ArrayList(); + for(int i=0; i < committee.size(); i++){ + int index = committee.get(i).intValue(); + int bitfieldBit = get_bitfield_bit(bitfield, i); + if((bitfieldBit & 1) == 1) attesting_indices.add(index); + } + return attesting_indices; + } + + /** + * Verify validity of ``indexed_attestation``. + * + * @param state + * @param indexed_attestation + * + * @see https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#validate_indexed_attestation + */ + public static void validate_indexed_attestation(BeaconState state, IndexedAttestation indexed_attestation){ + List bit_0_indices = indexed_attestation.getCustody_bit_0_indices(); + List bit_1_indices = indexed_attestation.getCustody_bit_1_indices(); + + checkArgument(bit_1_indices.size() == 0, "AttestationUtil.validate_indexed_attestation: Verify no index has custody bit equal to 1 [to be removed in phase 1]"); + checkArgument((bit_0_indices.size() + bit_1_indices.size()) <= MAX_INDICES_PER_ATTESTATION, "AttestationUtil.validate_indexed_attestation: Verify max number of indices"); + checkArgument(intersection(bit_0_indices, bit_1_indices).size() == 0, "AttestationUtil.validate_indexed_attestation: Verify index sets are disjoint"); + + //Verify indices are sorted + List bit_0_indices_sorted = new ArrayList(bit_0_indices); + Collections.sort(bit_0_indices_sorted); + List bit_1_indices_sorted = new ArrayList(bit_1_indices); + Collections.sort(bit_1_indices_sorted); + checkArgument(bit_0_indices.equals(bit_0_indices_sorted) && bit_1_indices.equals(bit_1_indices_sorted)); + + List validators = state.getValidator_registry(); + List pubkeys = new ArrayList(); + pubkeys.add(bls_aggregate_pubkeys(bit_0_indices.stream() + .map(i -> validators.get(i).getPubkey()).collect(Collectors.toList()))); + pubkeys.add(bls_aggregate_pubkeys(bit_1_indices.stream() + .map(i -> validators.get(i).getPubkey()).collect(Collectors.toList()))); + + List message_hashes = new ArrayList(); + message_hashes.add(new AttestationDataAndCustodyBit(indexed_attestation.getData(), false).hash_tree_root()); + message_hashes.add(new AttestationDataAndCustodyBit(indexed_attestation.getData(), true).hash_tree_root()); + + BLSSignature signature = indexed_attestation.getSignature(); + UnsignedLong domain = UnsignedLong.valueOf(get_domain(state, DOMAIN_ATTESTATION, indexed_attestation.getData().getTarget_epoch())); + //Verify aggregate signature + checkArgument(BLSVerify.bls_verify_multiple(pubkeys, message_hashes, signature, domain)); + } + + /** + * Returns the data slot for the provided AttestationData + * + * @param state + * @param data + * @return + * + * @see https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#get_attestation_data_slot + */ + public static UnsignedLong get_attestation_data_slot(BeaconState state, AttestationData data) { + UnsignedLong committee_count = get_epoch_committee_count(state, data.getTarget_epoch()); + UnsignedLong offset = (data.getCrosslink().getShard() + .plus(UnsignedLong.valueOf(SHARD_COUNT)) + .minus(get_epoch_start_shard(state, data.getTarget_epoch()))) + .mod(UnsignedLong.valueOf(SHARD_COUNT)); + return get_epoch_start_slot(data.getTarget_epoch()).plus(offset.dividedBy(committee_count.dividedBy(UnsignedLong.valueOf(SLOTS_PER_EPOCH)))); + } + + public static List intersection(List list1, List list2) { + List list = new ArrayList(); + + for (T t : list1) { + if(list2.contains(t)) { + list.add(t); + } + } + + return list; + } + } diff --git a/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/util/BeaconBlockUtil.java b/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/util/BeaconBlockUtil.java index 6c014f5ccde..badb2b943dc 100644 --- a/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/util/BeaconBlockUtil.java +++ b/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/util/BeaconBlockUtil.java @@ -24,20 +24,6 @@ public class BeaconBlockUtil { private static final ALogger LOG = new ALogger(BeaconBlockUtil.class.getName()); - /** - * Return the block header corresponding to a block with ``state_root`` set to ``ZERO_HASH``. - * - * @param block - * @return - */ - public static BeaconBlockHeader get_temporary_block_header(BeaconBlock block) { - return new BeaconBlockHeader( - UnsignedLong.valueOf(block.getSlot()), - block.getPrevious_block_root(), - Constants.ZERO_HASH, - block.getBody().hash_tree_root(), - Constants.EMPTY_SIGNATURE); - } /** * Get an empty ``BeaconBlock``. diff --git a/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/util/BeaconStateUtil.java b/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/util/BeaconStateUtil.java index fccfef92d3c..8cd823b667e 100644 --- a/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/util/BeaconStateUtil.java +++ b/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/util/BeaconStateUtil.java @@ -13,37 +13,8 @@ package tech.pegasys.artemis.datastructures.util; -import static com.google.common.base.Preconditions.checkArgument; -import static java.lang.Math.toIntExact; -import static tech.pegasys.artemis.datastructures.Constants.ACTIVATION_EXIT_DELAY; -import static tech.pegasys.artemis.datastructures.Constants.DOMAIN_ATTESTATION; -import static tech.pegasys.artemis.datastructures.Constants.DOMAIN_DEPOSIT; -import static tech.pegasys.artemis.datastructures.Constants.FAR_FUTURE_EPOCH; -import static tech.pegasys.artemis.datastructures.Constants.GENESIS_EPOCH; -import static tech.pegasys.artemis.datastructures.Constants.LATEST_ACTIVE_INDEX_ROOTS_LENGTH; -import static tech.pegasys.artemis.datastructures.Constants.LATEST_RANDAO_MIXES_LENGTH; -import static tech.pegasys.artemis.datastructures.Constants.LATEST_SLASHED_EXIT_LENGTH; -import static tech.pegasys.artemis.datastructures.Constants.MAX_DEPOSIT_AMOUNT; -import static tech.pegasys.artemis.datastructures.Constants.MAX_INDICES_PER_SLASHABLE_VOTE; -import static tech.pegasys.artemis.datastructures.Constants.SHARD_COUNT; -import static tech.pegasys.artemis.datastructures.Constants.SHUFFLE_ROUND_COUNT; -import static tech.pegasys.artemis.datastructures.Constants.SLOTS_PER_EPOCH; -import static tech.pegasys.artemis.datastructures.Constants.WHISTLEBLOWER_REWARD_QUOTIENT; -import static tech.pegasys.artemis.util.bls.BLSAggregate.bls_aggregate_pubkeys; -import static tech.pegasys.artemis.util.bls.BLSVerify.bls_verify; -import static tech.pegasys.artemis.util.bls.BLSVerify.bls_verify_multiple; - import com.google.common.annotations.VisibleForTesting; import com.google.common.primitives.UnsignedLong; -import java.nio.ByteOrder; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.ListIterator; -import java.util.Objects; -import java.util.stream.Collectors; -import java.util.stream.IntStream; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.crypto.Hash; @@ -66,6 +37,46 @@ import tech.pegasys.artemis.util.hashtree.HashTreeUtil; import tech.pegasys.artemis.util.hashtree.HashTreeUtil.SSZTypes; +import java.nio.ByteOrder; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Objects; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import static com.google.common.base.Preconditions.checkArgument; +import static java.lang.Math.toIntExact; +import static tech.pegasys.artemis.datastructures.Constants.ACTIVATION_EXIT_DELAY; +import static tech.pegasys.artemis.datastructures.Constants.CHURN_LIMIT_QUOTIENT; +import static tech.pegasys.artemis.datastructures.Constants.DOMAIN_ATTESTATION; +import static tech.pegasys.artemis.datastructures.Constants.DOMAIN_DEPOSIT; +import static tech.pegasys.artemis.datastructures.Constants.FAR_FUTURE_EPOCH; +import static tech.pegasys.artemis.datastructures.Constants.GENESIS_EPOCH; +import static tech.pegasys.artemis.datastructures.Constants.LATEST_ACTIVE_INDEX_ROOTS_LENGTH; +import static tech.pegasys.artemis.datastructures.Constants.LATEST_RANDAO_MIXES_LENGTH; +import static tech.pegasys.artemis.datastructures.Constants.LATEST_SLASHED_EXIT_LENGTH; +import static tech.pegasys.artemis.datastructures.Constants.MAX_DEPOSIT_AMOUNT; +import static tech.pegasys.artemis.datastructures.Constants.MAX_EFFECTIVE_BALANCE; +import static tech.pegasys.artemis.datastructures.Constants.MAX_INDICES_PER_SLASHABLE_VOTE; +import static tech.pegasys.artemis.datastructures.Constants.MIN_PER_EPOCH_CHURN_LIMIT; +import static tech.pegasys.artemis.datastructures.Constants.MIN_SEED_LOOKAHEAD; +import static tech.pegasys.artemis.datastructures.Constants.SHARD_COUNT; +import static tech.pegasys.artemis.datastructures.Constants.SHUFFLE_ROUND_COUNT; +import static tech.pegasys.artemis.datastructures.Constants.SLOTS_PER_EPOCH; +import static tech.pegasys.artemis.datastructures.Constants.SLOTS_PER_HISTORICAL_ROOT; +import static tech.pegasys.artemis.datastructures.Constants.TARGET_COMMITTEE_SIZE; +import static tech.pegasys.artemis.datastructures.Constants.WHISTLEBLOWER_REWARD_QUOTIENT; +import static tech.pegasys.artemis.datastructures.util.CrosslinkCommitteeUtil.get_crosslink_committee; +import static tech.pegasys.artemis.datastructures.util.CrosslinkCommitteeUtil.get_epoch_start_shard; +import static tech.pegasys.artemis.datastructures.util.ValidatorsUtil.get_active_validator_indices; +import static tech.pegasys.artemis.util.bls.BLSAggregate.bls_aggregate_pubkeys; +import static tech.pegasys.artemis.util.bls.BLSVerify.bls_verify; +import static tech.pegasys.artemis.util.bls.BLSVerify.bls_verify_multiple; + public class BeaconStateUtil { private static final ALogger LOG = new ALogger(BeaconStateUtil.class.getName()); @@ -103,7 +114,7 @@ public static BeaconStateWithCache get_genesis_beacon_state( } List active_validator_indices = - ValidatorsUtil.get_active_validator_indices( + get_active_validator_indices( state.getValidator_registry(), UnsignedLong.valueOf(GENESIS_EPOCH)); Bytes32 genesis_active_index_root = HashTreeUtil.hash_tree_root( @@ -126,7 +137,7 @@ public static BeaconStateWithCache get_genesis_beacon_state( * @param deposit */ public static void process_deposit(BeaconState state, Deposit deposit) { - DepositInput deposit_input = deposit.getDeposit_data().getDeposit_input(); + DepositInput deposit_input = deposit.getDeposit_data().getSignature(); // Should equal 8 bytes for deposit_data.amount + // 8 bytes for deposit_data.timestamp + @@ -223,269 +234,65 @@ public static boolean verify_merkle_branch( } /** - * Return the list of (committee, shard) tuples (implemented as CrosslinkCommittee) 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` - * - * @param state - The beacon state under consideration. - * @param slot - The slot number. - * @param registry_change - True if we are considering a registry change. - * @return The list of CrosslinkCommittees for the slot. - * @see get_crosslink_committees_at_slot - * - Spec v0.4 - */ - public static List get_crosslink_committees_at_slot( - BeaconState state, UnsignedLong slot, boolean registry_change) - throws IllegalArgumentException { - if (state instanceof BeaconStateWithCache - && ((BeaconStateWithCache) state).getCrossLinkCommitteesAtSlot(slot) != null) { - BeaconStateWithCache stateWithCash = (BeaconStateWithCache) state; - return stateWithCash.getCrossLinkCommitteesAtSlot(slot); - } else { - UnsignedLong epoch = slot_to_epoch(slot); - UnsignedLong current_epoch = get_current_epoch(state); - UnsignedLong previous_epoch = get_previous_epoch(state); - UnsignedLong next_epoch = get_next_epoch(state); - - checkArgument( - previous_epoch.compareTo(epoch) <= 0 && epoch.compareTo(next_epoch) <= 0, - "get_crosslink_committees_at_slot: epoch out of range"); - - UnsignedLong committees_per_epoch = UnsignedLong.ZERO; - UnsignedLong current_committees_per_epoch = UnsignedLong.ZERO; - Bytes32 seed = Bytes32.ZERO; - UnsignedLong shuffling_epoch = UnsignedLong.ZERO; - UnsignedLong shuffling_start_shard = UnsignedLong.ZERO; - - if (epoch.compareTo(current_epoch) == 0) { - - committees_per_epoch = get_current_epoch_committee_count(state); - seed = state.getCurrent_shuffling_seed(); - shuffling_epoch = state.getCurrent_shuffling_epoch(); - shuffling_start_shard = state.getCurrent_shuffling_start_shard(); - - } else if (epoch.compareTo(previous_epoch) == 0) { - - committees_per_epoch = get_previous_epoch_committee_count(state); - seed = state.getPrevious_shuffling_seed(); - shuffling_epoch = state.getPrevious_shuffling_epoch(); - shuffling_start_shard = state.getPrevious_shuffling_start_shard(); - - } else if (epoch.compareTo(next_epoch) == 0) { - - UnsignedLong epochs_since_last_registry_update = - current_epoch.minus(state.getValidator_registry_update_epoch()); - 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 - .getCurrent_shuffling_start_shard() - .plus(current_committees_per_epoch) - .mod(UnsignedLong.valueOf(SHARD_COUNT)); - } else if (epochs_since_last_registry_update.compareTo(UnsignedLong.ONE) > 0 - && 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.getCurrent_shuffling_start_shard(); - } else { - committees_per_epoch = get_current_epoch_committee_count(state); - seed = state.getCurrent_shuffling_seed(); - shuffling_epoch = state.getCurrent_shuffling_epoch(); - shuffling_start_shard = state.getCurrent_shuffling_start_shard(); - } - } - - List> shuffling = - get_shuffling(seed, state.getValidator_registry(), shuffling_epoch); - - UnsignedLong offset = slot.mod(UnsignedLong.valueOf(SLOTS_PER_EPOCH)); - UnsignedLong committees_per_slot = - committees_per_epoch.dividedBy(UnsignedLong.valueOf(SLOTS_PER_EPOCH)); - - UnsignedLong slot_start_shard = - shuffling_start_shard - .plus(committees_per_slot.times(offset)) - .mod(UnsignedLong.valueOf(Constants.SHARD_COUNT)); - - ArrayList crosslink_committees_at_slot = new ArrayList<>(); - for (long i = 0; i < committees_per_slot.longValue(); i++) { - CrosslinkCommittee committee = - new CrosslinkCommittee( - slot_start_shard.plus(UnsignedLong.ONE).mod(UnsignedLong.valueOf(SHARD_COUNT)), - shuffling.get( - committees_per_slot.times(offset).plus(UnsignedLong.valueOf(i)).intValue())); - crosslink_committees_at_slot.add(committee); - } - - // Client specific optimization - ((BeaconStateWithCache) state) - .setCrossLinkCommitteesAtSlot(crosslink_committees_at_slot, slot); - - return crosslink_committees_at_slot; - } - } - - /** This is a wrapper that defaults `registry_change` to false when it is not provided */ - public static List get_crosslink_committees_at_slot( - BeaconState state, UnsignedLong slot) throws IllegalArgumentException { - return get_crosslink_committees_at_slot(state, slot, false); - } - - /* - * TODO: Note from spec - Note: this definition and the next few definitions - * make heavy use of repetitive computing. Production implementations are - * expected to appropriately use caching/memoization to avoid redoing work. - */ - - /** - * Return the number of committees in the previous epoch of the given state. - * - * @param state - The state under consideration. - * @return The number of committees in the previous epoch. - * @see get_previous_epoch_committee_count - * - Spec v0.4 - */ - private static UnsignedLong get_previous_epoch_committee_count(BeaconState state) { - BeaconStateWithCache stateWithCash = (BeaconStateWithCache) state; - if (stateWithCash.getPreviousEpochCommitteeCount().compareTo(UnsignedLong.MAX_VALUE) < 0) { - return stateWithCash.getPreviousEpochCommitteeCount(); - } else { - List previous_active_validators = - ValidatorsUtil.get_active_validator_indices( - state.getValidator_registry(), state.getPrevious_shuffling_epoch()); - UnsignedLong count = - get_epoch_committee_count(UnsignedLong.valueOf(previous_active_validators.size())); - // Client specific optimization - stateWithCash.setPreviousEpochCommitteeCount(count); - return count; - } - } - - /** - * Returns the number of committees in the current epoch of the given state. - * - * @param state - The state under consideration. - * @return The number of committees in the current epoch. - * @see get_current_epoch_committee_count - * - Spec v0.4 - */ - public static UnsignedLong get_current_epoch_committee_count(BeaconState state) { - List current_active_validators = - ValidatorsUtil.get_active_validator_indices( - state.getValidator_registry(), state.getCurrent_shuffling_epoch()); - return get_epoch_committee_count(UnsignedLong.valueOf(current_active_validators.size())); - } - - /** - * Returns the number of committees in the next epoch of the given state. - * - * @param state - The state under consideration. - * @return The number of committees in the next epoch. - * @see get_next_epoch_committee_count - * - Spec v0.4 - */ - private static UnsignedLong get_next_epoch_committee_count(BeaconState state) { - List next_active_validators = - ValidatorsUtil.get_active_validator_indices( - state.getValidator_registry(), get_current_epoch(state).plus(UnsignedLong.ONE)); - return get_epoch_committee_count(UnsignedLong.valueOf(next_active_validators.size())); - } - - /** - * Generate a seed for the given epoch. + * Generate a seed for the given ``epoch``. * * @param state - The BeaconState under consideration. * @param epoch - The epoch to generate a seed for. * @return A generated seed for the given epoch. - * @see generate_seed - * - Spec v0.4 + * @throws IllegalArgumentException + * + * @see https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#generate_seed */ public static Bytes32 generate_seed(BeaconState state, UnsignedLong epoch) throws IllegalArgumentException { + UnsignedLong randaoIndex = epoch.plus(UnsignedLong.valueOf(LATEST_RANDAO_MIXES_LENGTH - MIN_SEED_LOOKAHEAD)); Bytes32 randao_mix = - get_randao_mix(state, epoch.minus(UnsignedLong.valueOf(Constants.MIN_SEED_LOOKAHEAD))); + get_randao_mix(state, randaoIndex); Bytes32 index_root = get_active_index_root(state, epoch); Bytes32 epochBytes = int_to_bytes32(epoch.longValue()); - return Hash.keccak256(Bytes.wrap(randao_mix, index_root, epochBytes)); + return Hash.sha2_256(Bytes.wrap(randao_mix, index_root, epochBytes)); } /** - * Returns the index root at a recent epoch. + * 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]. * * @param state - The BeaconState under consideration. * @param epoch - The epoch to get the index root for. - * @return The index root at a given recent epoch. - * @see get_active_index_root - * - Spec v0.4 + * @return + * + * @see https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#get_active_index_root */ public static Bytes32 get_active_index_root(BeaconState state, UnsignedLong epoch) { - checkArgument( - get_current_epoch(state) - .minus(UnsignedLong.valueOf(LATEST_ACTIVE_INDEX_ROOTS_LENGTH)) - .plus(UnsignedLong.valueOf(ACTIVATION_EXIT_DELAY)) - .compareTo(epoch) - < 0, - "get_active_index_root: first check"); - checkArgument( - epoch.compareTo(get_current_epoch(state).plus(UnsignedLong.valueOf(ACTIVATION_EXIT_DELAY))) - <= 0, - "get_active_index_root: second check"); - int index = epoch.mod(UnsignedLong.valueOf(LATEST_ACTIVE_INDEX_ROOTS_LENGTH)).intValue(); return state.getLatest_active_index_roots().get(index); } - public static Bytes32 getShard_block_root(BeaconState state, UnsignedLong shard) { - return state - .getLatest_crosslinks() - .get(toIntExact(shard.longValue()) % Constants.SHARD_COUNT) - .getCrosslink_data_root(); - } - /** - * Returns the effective balance (also known as "balance at stake") for a validator with the given - * index. + * Return the combined effective balance of the ``indices``. (1 Gwei minimum to avoid divisions by zero.) * - * @param state - The BeaconState under consideration. - * @param index - The index of the validator to consider. - * @return The smaller of either the validator's balance at stake or MAX_DEPOSIT_AMOUNT. - * @see get_effective_balance - * - Spec v0.4 - */ - public static UnsignedLong get_effective_balance(BeaconState state, int index) { - return min( - state.getValidator_balances().get(index), - UnsignedLong.valueOf(Constants.MAX_DEPOSIT_AMOUNT)); - } - - /** - * Adds and returns the effective balances for the validators referenced by the given indices. + * @param state + * @param indices + * @return * - * @param state - The current BeaconState. - * @param validators - A list of validator indices to get the total balance for. - * @return The combined effective balance of the list of validators. - * @see get_total_balance - * - Spec v0.4 + * @see https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#get_total_balance */ - public static UnsignedLong get_total_balance(BeaconState state, List validators) { - UnsignedLong total_balance = UnsignedLong.ZERO; - for (Integer index : validators) { - total_balance = total_balance.plus(BeaconStateUtil.get_effective_balance(state, index)); + public static UnsignedLong get_total_balance(BeaconState state, List indices){ + UnsignedLong sum = UnsignedLong.ZERO; + Iterator itr = indices.iterator(); + List validator_registry = state.getValidator_registry(); + while(itr.hasNext()){ + sum = sum.plus(validator_registry.get(itr.next().intValue()).getEffective_balance()); } - return total_balance; + return max(sum, UnsignedLong.ONE); + } + + public static Bytes32 getShard_block_root(BeaconState state, UnsignedLong shard) { + return state + .getLatest_crosslinks() + .get(toIntExact(shard.longValue()) % Constants.SHARD_COUNT) + .getCrosslink_data_root(); } /** @@ -501,13 +308,18 @@ public static UnsignedLong slot_to_epoch(UnsignedLong slot) { return slot.dividedBy(UnsignedLong.valueOf(SLOTS_PER_EPOCH)); } - /** Taken from 6.1 */ + /** + * Return the previous epoch of the given ``state``. + * Return the current epoch if it's genesis epoch. + * + * @param state + * @return + * + * @see https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#get_previous_epoch + */ public static UnsignedLong get_previous_epoch(BeaconState state) { - UnsignedLong current_epoch_minus_one = get_current_epoch(state).minus(UnsignedLong.ONE); - if (current_epoch_minus_one.compareTo(UnsignedLong.valueOf(GENESIS_EPOCH)) < 0) { - return UnsignedLong.valueOf(GENESIS_EPOCH); - } - return current_epoch_minus_one; + UnsignedLong current_epoch = get_current_epoch(state); + return (current_epoch.equals(UnsignedLong.valueOf(GENESIS_EPOCH))) ? UnsignedLong.valueOf(GENESIS_EPOCH) : current_epoch.minus(UnsignedLong.ONE); } /** @@ -632,201 +444,50 @@ public static void slash_validator(BeaconState state, int index) { } /** - * Set the validator with the given ``index`` as withdrawable - * ``MIN_VALIDATOR_WITHDRAWABILITY_DELAY`` after the current epoch. Note that this function - * mutates ``state``. - * - * @param state - * @param index - */ - public static void prepare_validator_for_withdrawal(BeaconState state, int index) { - Validator validator = state.getValidator_registry().get(index); - validator.setWithdrawable_epoch( - get_current_epoch(state) - .plus(UnsignedLong.valueOf(Constants.MIN_VALIDATOR_WITHDRAWABILITY_DELAY))); - } - - public static Bytes32 get_randao_mix(BeaconState state, UnsignedLong epoch) { - checkArgument( - get_current_epoch(state) - .minus(UnsignedLong.valueOf(LATEST_RANDAO_MIXES_LENGTH)) - .compareTo(epoch) - < 0, - "get_randao_mix: first check"); - checkArgument(epoch.compareTo(get_current_epoch(state)) <= 0, "get_randao_mix: second check"); - UnsignedLong index = epoch.mod(UnsignedLong.valueOf(LATEST_RANDAO_MIXES_LENGTH)); - return state.getLatest_randao_mixes().get(index.intValue()); - } - - /** - * Returns the block root at a recent slot. + * Return the block root at a recent ``epoch``. * * @param state - The BeaconState under consideration. - * @param slot - The slot to return the block root for. - * @return The block root at the given slot. - * @see get_block_root - * - Spec v0.4 + * @param epoch + * @return + * + * @see https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#get_block_root */ - public static Bytes32 get_block_root(BeaconState state, UnsignedLong slot) { - checkArgument( - slot.compareTo(state.getSlot()) < 0, - "checkArgument threw an exception in get_block_root()"); - checkArgument( - state - .getSlot() - .compareTo(slot.plus(UnsignedLong.valueOf(Constants.SLOTS_PER_HISTORICAL_ROOT))) - <= 0, - "checkArgument threw an exception in get_block_root()"); - // Todo: Remove .intValue() as soon as our list wrapper supports unsigned longs - return state - .getLatest_block_roots() - .get(slot.mod(UnsignedLong.valueOf(Constants.SLOTS_PER_HISTORICAL_ROOT)).intValue()); + public static Bytes32 get_block_root(BeaconState state, UnsignedLong epoch) { + return get_block_root_at_slot(state, get_epoch_start_slot(epoch)); } /** - * Return the state root at a recent ``slot``. + * Return the number of committees at ``epoch``. * * @param state - * @param slot + * @param epoch * @return - */ - public static Bytes32 get_state_root(BeaconState state, UnsignedLong slot) { - checkArgument( - state - .getSlot() - .compareTo(slot.plus(UnsignedLong.valueOf(Constants.SLOTS_PER_HISTORICAL_ROOT))) - <= 0, - "checkArgument threw an exception in get_state_root()"); - checkArgument( - slot.compareTo(state.getSlot()) < 0, - "checkArgument threw an exception in get_state_root()"); - // Todo: Remove .intValue() as soon as our list wrapper supports unsigned longs - return state - .getLatest_state_roots() - .get(slot.mod(UnsignedLong.valueOf(Constants.SLOTS_PER_HISTORICAL_ROOT)).intValue()); - } - - /** - * Returns the number of committees in one epoch. * - * @param active_validator_count - The number of active validators. - * @return The number of committees in one epoch. - * @see get_epoch_committee_count - * - Spec v0.4 + * @see https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#get_epoch_committee_count */ - public static UnsignedLong get_epoch_committee_count(UnsignedLong active_validator_count) { - + public static UnsignedLong get_epoch_committee_count(BeaconState state, UnsignedLong epoch){ + List active_validator_indices = get_active_validator_indices(state, epoch); return max( UnsignedLong.ONE, min( - UnsignedLong.valueOf(Constants.SHARD_COUNT) - .dividedBy(UnsignedLong.valueOf(SLOTS_PER_EPOCH)), - active_validator_count - .dividedBy(UnsignedLong.valueOf(SLOTS_PER_EPOCH)) - .dividedBy(UnsignedLong.valueOf(Constants.TARGET_COMMITTEE_SIZE)))) - .times(UnsignedLong.valueOf(SLOTS_PER_EPOCH)); + UnsignedLong.valueOf(Math.floorDiv(SHARD_COUNT, SLOTS_PER_EPOCH)), + UnsignedLong.valueOf(active_validator_indices.size()).dividedBy(UnsignedLong.valueOf(SLOTS_PER_EPOCH)).dividedBy(UnsignedLong.valueOf(TARGET_COMMITTEE_SIZE)) + ) + ).times(UnsignedLong.valueOf(SLOTS_PER_EPOCH)); } /** - * Shuffle active validators and splits into crosslink committees. + * Return the randao mix at a recent ``epoch``. + * ``epoch`` expected to be between (current_epoch - LATEST_RANDAO_MIXES_LENGTH, current_epoch]. + * @param state + * @param epoch + * @return * - * @param seed - A shuffling seed. - * @param validators - The list of validators to shuffle. - * @param epoch - Epoch under consideration. - * @return A list of committees (each of list of validator indices) - * @see get_shuffling - * - Spec v0.4 + * @see https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#get_randao_mix */ - public static List> get_shuffling( - Bytes32 seed, List validators, UnsignedLong epoch) throws IllegalStateException { - - List active_validator_indices = - ValidatorsUtil.get_active_validator_indices(validators, epoch); - - int length = active_validator_indices.size(); - - List shuffled_indices = new ArrayList<>(Collections.nCopies(length, 0)); - int[] shuffling = shuffle(length, seed); - IntStream.range(0, length) - .parallel() - .forEach(i -> shuffled_indices.set(i, active_validator_indices.get(shuffling[i]))); - - int committeesPerEpoch = get_epoch_committee_count(UnsignedLong.valueOf(length)).intValue(); - - return split(shuffled_indices, committeesPerEpoch); - } - - /** - * 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. - * - * @param index The index in the permuatation we wish to get the value of. - * @param list_size The size of the list from which the element is taken. - * @param seed Initial seed value used for randomization. - * @return The index from the original list that is now at position `index` - * @see get_permuted_index - * - Spec v0.4 - */ - @VisibleForTesting - public static int get_permuted_index(int index, int list_size, Bytes32 seed) { - checkArgument(index < list_size, "get_permuted_index(): index greater than list size"); - - // The spec says that we should handle up to 2^40 validators, but we can't do this, - // so we just fall back to int (2^31 validators). - // checkArgument(list_size <= 1099511627776L); // 2^40 - - /* - * In the following, great care is needed around signed and unsigned values. - * Note that the % (modulo) operator in Java behaves differently from the - * modulo operator in python: - * Python -1 % 13 = 12 - * Java -1 % 13 = -1 - * - * Using UnsignedLong doesn't help us as some quantities can legitimately be negative. - */ - - int indexRet = index; - byte[] powerOfTwoNumbers = {1, 2, 4, 8, 16, 32, 64, (byte) 128}; - - for (int round = 0; round < SHUFFLE_ROUND_COUNT; round++) { - - Bytes roundAsByte = Bytes.of((byte) round); - - // This needs to be unsigned modulo. - int pivot = - toIntExact( - Long.remainderUnsigned( - bytes_to_int(Hash.keccak256(Bytes.wrap(seed, roundAsByte)).slice(0, 8)), - list_size)); - int flip = (pivot - indexRet) % list_size; - if (flip < 0) { - // Account for flip being negative - flip += list_size; - } - - int position = (indexRet < flip) ? flip : indexRet; - - Bytes positionDiv256 = int_to_bytes(position / 256, 4); - Bytes source = Hash.keccak256(Bytes.wrap(seed, roundAsByte, positionDiv256)); - - // The byte type is signed in Java, but the right shift should be fine as we just use bit 0. - // But we can't use % in the normal way because of signedness, so we `& 1` instead. - byte theByte = source.get(position % 256 / 8); - byte theMask = powerOfTwoNumbers[position % 8]; - if ((theByte & theMask) != 0) { - indexRet = flip; - } - } - - return indexRet; + public static Bytes32 get_randao_mix(BeaconState state, UnsignedLong epoch){ + int index = epoch.mod(UnsignedLong.valueOf(LATEST_RANDAO_MIXES_LENGTH)).intValue(); + return state.getLatest_randao_mixes().get(index); } /** @@ -923,67 +584,36 @@ public static int bytes3ToInt(Bytes src, int pos) { } /** - * Splits ``values`` into ``split_count`` pieces. + * Returns the index of the proposer for the current epoch * - * @param values The original list of validators. - * @param split_count The number of pieces to split the array into. - * @return The list of validators split into split_count pieces. - * @see split - * - Spec v0.4 - */ - public static List> split(List values, int split_count) { - checkArgument(split_count > 0, "Expected positive split_count but got %s", split_count); - - int list_length = values.size(); - List> split_arr = new ArrayList<>(split_count); - - for (int i = 0; i < split_count; i++) { - int startIndex = list_length * i / split_count; - int endIndex = list_length * (i + 1) / split_count; - List new_split = new ArrayList<>(); - for (int j = startIndex; j < endIndex; j++) { - new_split.add(values.get(j)); - } - split_arr.add(new_split); - } - return split_arr; - } - - /** - * Checks if the numerical value provided is a power of 2. + * @param state + * @return * - * @param value - The number under consideration. - * @return True if value is an exact power of 2, false otherwise. - * @see is_power_of_two - * - Spec v0.4 + * @see https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#get_beacon_proposer_index */ - public static boolean is_power_of_two(UnsignedLong value) { - long longValue = value.longValue(); - return longValue > 0 && (longValue & (longValue - 1)) == 0; - } - public static int get_beacon_proposer_index( - BeaconState state, UnsignedLong slot, boolean registry_change) - throws IllegalArgumentException { - UnsignedLong epoch = slot_to_epoch(slot); - UnsignedLong current_epoch = get_current_epoch(state); - UnsignedLong previous_epoch = get_previous_epoch(state); - UnsignedLong next_epoch = current_epoch.plus(UnsignedLong.ONE); - - checkArgument( - previous_epoch.compareTo(epoch) <= 0 && epoch.compareTo(next_epoch) <= 0, - "get_beacon_proposer_index: slot not in range"); - - List first_committee = - get_crosslink_committees_at_slot(state, slot, registry_change).get(0).getCommittee(); - // TODO: replace slot.intValue() with an UnsignedLong value - return first_committee.get(epoch.intValue() % first_committee.size()); - } - - public static int get_beacon_proposer_index(BeaconState state, UnsignedLong slot) { - return get_beacon_proposer_index(state, slot, false); + BeaconState state) { + UnsignedLong epoch = get_current_epoch(state); + UnsignedLong committees_per_slot = get_epoch_committee_count(state, epoch).dividedBy(UnsignedLong.valueOf(SLOTS_PER_EPOCH)); + UnsignedLong offset = committees_per_slot.times(state.getSlot().mod(UnsignedLong.valueOf(SLOTS_PER_EPOCH))); + UnsignedLong shard = (get_epoch_start_shard(state, epoch).plus(offset)).mod(UnsignedLong.valueOf(SHARD_COUNT)); + + List first_committee = get_crosslink_committee(state, epoch, shard); + int MAX_RANDOM_BYTE = ((int)(Math.pow(2.0d, 8.0d))) - 1; + Bytes seed = generate_seed(state, epoch); + int i = 0; + while(true){ + int index = epoch.plus(UnsignedLong.valueOf(i)).mod(UnsignedLong.valueOf(first_committee.size())).intValue(); + int candidate_index = first_committee.get(index).intValue(); + Bytes digest = Hash.sha2_256(Bytes.concatenate(seed, int_to_bytes(Math.floorDiv(i, 32), 8))); + byte random_byte = digest.get(i % 32); + UnsignedLong effective_balance = state.getValidator_registry().get(candidate_index).getEffective_balance(); + + UnsignedLong minRandomBalance = effective_balance.times(UnsignedLong.valueOf(MAX_RANDOM_BYTE)); + UnsignedLong maxRandomBalance = UnsignedLong.valueOf(MAX_EFFECTIVE_BALANCE * random_byte); + if(minRandomBalance.compareTo(maxRandomBalance) >= 0) return candidate_index; + i++; + } } /** @@ -1018,30 +648,49 @@ public static UnsignedLong max(UnsignedLong value1, UnsignedLong value2) { } /** - * TODO It may make sense to move this to {@link Fork}. - * - *

Get the domain number that represents the fork meta and signature domain. + * Return the signature domain (fork version concatenated with domain type) of a message. * - * @param fork - The Fork to retrieve the verion for. - * @param epoch - The epoch to retrieve the fork version for. See {@link - * #get_fork_version(Fork,UnsignedLong)} - * @param domain_type - The domain type. See - * https://github.com/ethereum/eth2.0-specs/blob/v0.4.0/specs/core/0_beacon-chain.md#signature-domains + * @param state + * @param domain_type + * @param message_epoch * @return The fork version and signature domain. This format ((fork version << 32) + * SignatureDomain) is used to partition BLS signatures. - * @see get_domain - * - Spec v0.4 + * + * @see https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#get_domain + */ + public static long get_domain(BeaconState state, int domain_type, UnsignedLong message_epoch) { + UnsignedLong epoch = (message_epoch == null) ? get_current_epoch(state) : message_epoch; + Bytes fork_version = (epoch.compareTo(state.getFork().getEpoch()) < 0) ? state.getFork().getPrevious_version() : state.getFork().getCurrent_version(); + return bls_domain(domain_type, fork_version); + } + + /** + * Return the bls domain given by the ``domain_type`` and optional 4 byte ``fork_version`` (defaults to zero). + * + * @param domain_type + * @param fork_version + * @return + * + * @see https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#bls_domain */ - public static UnsignedLong get_domain(Fork fork, UnsignedLong epoch, int domain_type) { - // TODO Investigate this further: - // We deviate from the spec, adding domain_type first then concatting fork version on to it. - // The spec does this in the opposite order. It smells a lot like an endianness problem. - // The question is, it is Java/us, or is it a spec bug. - return UnsignedLong.valueOf( - bytes_to_int(Bytes.wrap(int_to_bytes(domain_type, 4), get_fork_version(fork, epoch)))); + public static long bls_domain(int domain_type, Bytes fork_version){ + return bytes_to_int(Bytes.concatenate(int_to_bytes(domain_type, 4), fork_version)); } + /** + * Return the churn limit based on the active validator count. + * + * @param state + * @return + * + * @see https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#get_churn_limit + */ + public static UnsignedLong get_churn_limit(BeaconState state){ + return max(UnsignedLong.valueOf(MIN_PER_EPOCH_CHURN_LIMIT), + UnsignedLong.valueOf(Math.floorDiv(get_active_validator_indices(state, get_current_epoch(state)).size(), CHURN_LIMIT_QUOTIENT))); + } + + /** * Return the epoch at which an activation or exit triggered in `epoch` takes effect. g * @@ -1167,76 +816,6 @@ public static boolean verify_slashable_attestation( return bls_verify_multiple(pubkeys, message_hashes, signature, domain); } - /** - * TODO It may make sense to move this to {@link Fork}. - * - *

Returns the fork version of the given epoch. - * - * @param fork - The Fork to retrieve the version for. - * @param epoch - The epoch to retrieve the fork version for. - * @return The fork version of the given epoch. (previousVersion if epoch < fork.epoch, otherwise - * currentVersion) - * @see get_fork_version - * - Spec v0.4 - */ - public static Bytes get_fork_version(Fork fork, UnsignedLong epoch) { - if (epoch.compareTo(fork.getEpoch()) < 0) { - return fork.getPrevious_version(); - } else { - return fork.getCurrent_version(); - } - } - - /** - * Returns the participant indices for the attestation_data and bitfield. - * - * @param state - The BeaconState under consideration. - * @param attestation_data - The AttestationData under consideration. - * @param bitfield - The participation bitfield under consideration. - * @return The participant indices for the attestation_data and participation_bitfield. - * @see get_attestation_participants - * - Spec v0.4 - */ - public static ArrayList get_attestation_participants( - BeaconState state, AttestationData attestation_data, Bytes bitfield) - throws IllegalArgumentException { - - // Find the committee in the list with the desired shard - List crosslink_committees = - BeaconStateUtil.get_crosslink_committees_at_slot(state, attestation_data.getSlot()); - - checkArgument( - crosslink_committees.stream() - .map(i -> i.getShard()) - .collect(Collectors.toList()) - .contains(attestation_data.getShard()), - "get_attestation_participants: first check"); - - CrosslinkCommittee crosslink_committee = null; - for (CrosslinkCommittee committee : crosslink_committees) { - if (committee.getShard().equals(attestation_data.getShard())) { - crosslink_committee = committee; - break; - } - } - - checkArgument( - verify_bitfield(bitfield, crosslink_committee.getCommittee().size()), - "checkArgument threw and exception in get_attestation_participants()"); - - // Find the participating attesters in the committee - ArrayList participants = new ArrayList<>(); - for (int i = 0; i < crosslink_committee.getCommitteeSize(); i++) { - int participation_bit = get_bitfield_bit(Bytes.wrap(bitfield), i); - if (participation_bit == 1) { - participants.add(crosslink_committee.getCommittee().get(i)); - } - } - return participants; - } - /** Activate the validator with the given 'index'. Note that this function mutates 'state'. */ @VisibleForTesting public static void activate_validator(BeaconState state, int index, boolean is_genesis) { @@ -1248,41 +827,6 @@ public static void activate_validator(BeaconState state, int index, boolean is_g BeaconStateUtil.get_current_epoch(state))); } - /** - * Check if ``attestation_data_1`` and ``attestation_data_2`` have the same target. - * - * @param attestation_data_1 - The first AttestationData to check. - * @param attestation_data_2 - The second AttestationData to check. - * @return True if the provided 'AttestationData' are slashable due to a 'double vote', false - * otherwise. - * @see is_double_vote - * - Spec v0.4 - */ - public static boolean is_double_vote( - AttestationData attestation_data_1, AttestationData attestation_data_2) { - UnsignedLong target_epoch_1 = slot_to_epoch(attestation_data_1.getSlot()); - UnsignedLong target_epoch_2 = slot_to_epoch(attestation_data_2.getSlot()); - return target_epoch_1.compareTo(target_epoch_2) == 0; - } - - /** - * Check if ``attestation_data_1`` surrounds ``attestation_data_2``. - * - * @param attestation_data_1 - * @param attestation_data_2 - * @return - */ - public static boolean is_surround_vote( - AttestationData attestation_data_1, AttestationData attestation_data_2) { - UnsignedLong source_epoch_1 = attestation_data_1.getSource_epoch(); - UnsignedLong source_epoch_2 = attestation_data_2.getSource_epoch(); - UnsignedLong target_epoch_1 = slot_to_epoch(attestation_data_1.getSlot()); - UnsignedLong target_epoch_2 = slot_to_epoch(attestation_data_2.getSlot()); - return source_epoch_1.compareTo(source_epoch_2) < 0 - && target_epoch_2.compareTo(target_epoch_1) < 0; - } - /** * The largest integer 'x' such that 'x**2' is less than 'n'. * @@ -1347,4 +891,40 @@ public static Bytes32 int_to_bytes32(UnsignedLong value) { public static long bytes_to_int(Bytes data) { return data.toLong(ByteOrder.LITTLE_ENDIAN); } + + /** + * Return the block root at a recent ``slot``. + * + * @param state + * @param slot + * @return + * + * @see https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#get_block_root_at_slot + */ + public static Bytes32 get_block_root_at_slot(BeaconState state, UnsignedLong slot){ + UnsignedLong slotPlusHistoricalRoot = slot.plus(UnsignedLong.valueOf(SLOTS_PER_HISTORICAL_ROOT)); + checkArgument(slot.compareTo(state.getSlot()) < 0 && + state.getSlot().compareTo(slotPlusHistoricalRoot) <= 0 + , "BeaconStateUtil.get_block_root_at_slot"); + int latestBlockRootIndex = slot.mod(UnsignedLong.valueOf(SLOTS_PER_HISTORICAL_ROOT)).intValue(); + return state.getLatest_block_roots().get(latestBlockRootIndex); + } + + /** + * @param m + * @param n + * @return + */ + public static int safeMod(int m, int n){ + return ((n % m) + m) % m; + } + + /** + * @param m + * @param n + * @return + */ + public static long safeMod(long m, long n){ + return ((n % m) + m) % m; + } } diff --git a/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/util/CrosslinkCommitteeUtil.java b/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/util/CrosslinkCommitteeUtil.java index b6bf5af987a..142cc2b3ad4 100644 --- a/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/util/CrosslinkCommitteeUtil.java +++ b/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/util/CrosslinkCommitteeUtil.java @@ -14,31 +14,140 @@ package tech.pegasys.artemis.datastructures.util; import com.google.common.primitives.UnsignedLong; -import java.util.List; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; +import org.apache.tuweni.crypto.Hash; import tech.pegasys.artemis.datastructures.state.BeaconState; -import tech.pegasys.artemis.datastructures.state.Validator; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import static com.google.common.base.Preconditions.checkArgument; +import static java.lang.Math.toIntExact; +import static tech.pegasys.artemis.datastructures.Constants.SHARD_COUNT; +import static tech.pegasys.artemis.datastructures.Constants.SHUFFLE_ROUND_COUNT; +import static tech.pegasys.artemis.datastructures.Constants.SLOTS_PER_EPOCH; +import static tech.pegasys.artemis.datastructures.util.BeaconStateUtil.bytes_to_int; +import static tech.pegasys.artemis.datastructures.util.BeaconStateUtil.generate_seed; +import static tech.pegasys.artemis.datastructures.util.BeaconStateUtil.get_current_epoch; +import static tech.pegasys.artemis.datastructures.util.BeaconStateUtil.get_epoch_committee_count; +import static tech.pegasys.artemis.datastructures.util.BeaconStateUtil.int_to_bytes; +import static tech.pegasys.artemis.datastructures.util.BeaconStateUtil.max; +import static tech.pegasys.artemis.datastructures.util.BeaconStateUtil.min; +import static tech.pegasys.artemis.datastructures.util.BeaconStateUtil.safeMod; +import static tech.pegasys.artemis.datastructures.util.ValidatorsUtil.get_active_validator_indices; public class CrosslinkCommitteeUtil { - // Return the number of committees in the previous epoch of the given ``state` - public static int get_previous_epoch_committee_count(BeaconState state) { - List previous_active_validators = - ValidatorsUtil.get_active_validators( - state.getValidator_registry(), state.getPrevious_shuffling_epoch()); - return previous_active_validators.size(); + + /** + * Return the shuffled validator index corresponding to ``seed`` (and ``index_count``). + * + * @param index + * @param index_count + * @param seed + * @return + * + * @see https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#get_shuffled_index + */ + public static Integer get_shuffled_index(int index, int index_count, Bytes32 seed){ + checkArgument(index < index_count, "CrosslinkCommitteeUtil.get_shuffled_index1"); + checkArgument(index_count <= Math.pow(2, 40), "CrosslinkCommitteeUtil.get_shuffled_index2"); + + //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(int round = 0; round < SHUFFLE_ROUND_COUNT; round++){ + Bytes roundBytes = int_to_bytes(round, 1); + + Bytes32 pivotHashValue = Hash.sha2_256(Bytes.concatenate(seed, roundBytes)); + Bytes pivotHashSubArray = Bytes.wrap(ArrayUtils.subarray(pivotHashValue.toArray(), 0, 8)); + int pivot = safeMod(((int)bytes_to_int(pivotHashSubArray)) ,index_count); + + int flip = safeMod((pivot + index_count - index), index_count); + long position = max(UnsignedLong.valueOf(index), UnsignedLong.valueOf(flip)).longValue(); + + Bytes sourceBytes = Bytes.concatenate(seed, roundBytes, int_to_bytes(Math.floorDiv(position, 256l), 4)); + Bytes32 source = Hash.sha2_256(sourceBytes); + + int sourceByteIndex = toIntExact(Math.floorDiv(safeMod(position, 256), 8l)); + byte byteValue = source.get(sourceByteIndex); + int bit = safeMod((byteValue >> (safeMod(position, 8))), 2); + index = (bit == 1) ? flip : index; + } + return index; + } + + /** + * Computes indices of a new committee based upon the seed parameter + * + * @param indices + * @param seed + * @param index + * @param count + * @return + * + * @see https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#compute_committee + */ + public static List compute_committee(List indices, Bytes32 seed, int index, int count){ + int start = Math.floorDiv(indices.size() * index, count); + int end = Math.floorDiv(indices.size() * (index + 1), count); + return IntStream.range(start, end).map(i -> indices.get(get_shuffled_index(i, indices.size(), seed))).boxed().collect(Collectors.toList()); } - // Return the number of committees in the previous epoch of the given ``state` - public static int get_current_epoch_committee_count(BeaconState state) { - List previous_active_validators = - ValidatorsUtil.get_active_validators( - state.getValidator_registry(), state.getCurrent_shuffling_epoch()); - return previous_active_validators.size(); + + /** + * Convenience method for getting a crosslink committee + * + * @param state + * @param epoch + * @param shard + * @return + * + * @see https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#get_crosslink_committee + */ + public static List get_crosslink_committee(BeaconState state, UnsignedLong epoch, UnsignedLong shard){ + int index = shard.plus(UnsignedLong.valueOf(SHARD_COUNT).minus(get_epoch_start_shard(state, epoch))) + .mod(UnsignedLong.valueOf(SHARD_COUNT)) + .intValue(); + return compute_committee( + get_active_validator_indices(state, epoch), + generate_seed(state, epoch), + index, + get_epoch_committee_count(state, epoch).intValue() + ); + } + + /** + * Returns the index of a start shard for the provided epoch + * + * @param state + * @param epoch + * @return + * + * @see https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#get_epoch_start_shard + */ + public static UnsignedLong get_epoch_start_shard(BeaconState state, UnsignedLong epoch){ + checkArgument(epoch.compareTo(get_current_epoch(state).plus(UnsignedLong.ONE)) <= 0, "CrosslinkCommitteeUtil.get_epoch_start_shard"); + UnsignedLong check_epoch = get_current_epoch(state).plus(UnsignedLong.ONE); + UnsignedLong shard = state.getLatest_start_shard().plus(get_shard_delta(state, get_current_epoch(state))).mod(UnsignedLong.valueOf(SHARD_COUNT)); + + while(check_epoch.compareTo(epoch) > 0){ + check_epoch = check_epoch.minus(UnsignedLong.ONE); + shard = shard.plus(UnsignedLong.valueOf(SHARD_COUNT)).minus(get_shard_delta(state, check_epoch)).mod(UnsignedLong.valueOf(SHARD_COUNT)); + } + return shard; } - public static int get_next_epoch_committee_count(BeaconState state) { - List previous_active_validators = - ValidatorsUtil.get_active_validators( - state.getValidator_registry(), - state.getCurrent_shuffling_epoch().plus(UnsignedLong.ONE)); - return previous_active_validators.size(); + /** + * Return the number of shards to increment ``state.latest_start_shard`` during ``epoch``. + * + * @param state + * @param epoch + * @return + * + * @see https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#get_shard_delta + */ + public static UnsignedLong get_shard_delta(BeaconState state, UnsignedLong epoch){ + return min(get_epoch_committee_count(state, epoch), UnsignedLong.valueOf(SHARD_COUNT - Math.floorDiv(SHARD_COUNT , SLOTS_PER_EPOCH))); } } diff --git a/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/util/DepositUtil.java b/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/util/DepositUtil.java index 6f0f37c5ed0..b40478111b8 100644 --- a/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/util/DepositUtil.java +++ b/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/util/DepositUtil.java @@ -94,7 +94,7 @@ public static Bytes32 calculatePubKeyRoot(Deposit deposit) { Bytes.concatenate( deposit .getDeposit_data() - .getDeposit_input() + .getSignature() .getPubkey() .getPublicKey() .toBytesCompressed(), @@ -108,7 +108,7 @@ public static Bytes32 calculateSignatureRoot(Deposit deposit) { Arrays.copyOfRange( deposit .getDeposit_data() - .getDeposit_input() + .getSignature() .getProof_of_possession() .getSignature() .toBytesCompressed() @@ -122,7 +122,7 @@ public static Bytes32 calculateSignatureRoot(Deposit deposit) { Arrays.copyOfRange( deposit .getDeposit_data() - .getDeposit_input() + .getSignature() .getProof_of_possession() .getSignature() .toBytesCompressed() @@ -139,7 +139,7 @@ public static Bytes32 calculateBranchValue( Hash.sha2_256( Bytes.concatenate( pubkey_root, - deposit.getDeposit_data().getDeposit_input().getWithdrawal_credentials())); + deposit.getDeposit_data().getSignature().getWithdrawal_credentials())); Bytes32 value_end = Hash.sha2_256( Bytes.concatenate( diff --git a/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/util/ValidatorsUtil.java b/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/util/ValidatorsUtil.java index 8e6d71a347f..f153da0ba76 100644 --- a/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/util/ValidatorsUtil.java +++ b/ethereum/datastructures/src/main/java/tech/pegasys/artemis/datastructures/util/ValidatorsUtil.java @@ -15,14 +15,15 @@ import com.google.common.collect.Sets; import com.google.common.primitives.UnsignedLong; +import tech.pegasys.artemis.datastructures.state.BeaconState; +import tech.pegasys.artemis.datastructures.state.Validator; + import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.IntStream; -import tech.pegasys.artemis.datastructures.state.BeaconState; -import tech.pegasys.artemis.datastructures.state.Validator; public class ValidatorsUtil { @@ -63,18 +64,18 @@ public static List get_active_validators( } /** - * Get indices of active validators from ``validators``. + * Get active validator indices at ``epoch``. * - * @param validators - The list of validators under consideration. + * @param state - Current BeaconState * @param epoch - The epoch under consideration. * @return A list of indices representing the active validators for the given epoch. - * @see get_active_validator_indices - * - Spec v0.4 + * + * @see https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#get_active_validator_indices */ public static List get_active_validator_indices( - List validators, UnsignedLong epoch) { + BeaconState state, UnsignedLong epoch) { List active_validator_indices = Collections.synchronizedList(new ArrayList<>()); + List validators = state.getValidator_registry(); IntStream.range(0, validators.size()) .parallel() .forEachOrdered( @@ -117,4 +118,44 @@ public static List get_validators_not_present(List validator_i set_of_indices.removeAll(set_of_validator_indices); return new ArrayList<>(set_of_indices); } + + /** + * Decrease validator balance by ``delta`` with underflow protection. + * + * @param state + * @param index + * @param delta + * + * @see https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#decrease_balance + */ + public static void decrease_balance(BeaconState state, int index, UnsignedLong delta){ + UnsignedLong deltaBalance = delta.compareTo(state.getBalances().get(index)) > 0 ? UnsignedLong.ZERO : state.getBalances().get(index).minus(delta); + state.getBalances().set(index, deltaBalance); + } + + /** + * Increase validator balance by ``delta``. + * + * @param state + * @param index + * @param delta + * + * @see https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#increase_balance + */ + public static void increase_balance(BeaconState state, int index, UnsignedLong delta){ + state.getBalances().set(index, state.getBalances().get(index).plus(delta)); + } + + /** + * Determines if a validator has a balance that can be slashed + * + * @param validator + * @param epoch + * @return + * + * @see https://github.com/ethereum/eth2.0-specs/blob/v0.7.1/specs/core/0_beacon-chain.md#is_slashable_validator + */ + public static boolean is_slashable_validator(Validator validator, UnsignedLong epoch){ + return !validator.isSlashed() && (validator.getActivation_epoch().compareTo(epoch) <= 0 && epoch.compareTo(validator.getWithdrawable_epoch()) < 0); + } } diff --git a/ethereum/datastructures/src/test/java/tech/pegasys/artemis/datastructures/util/BeaconStateUtilTest.java b/ethereum/datastructures/src/test/java/tech/pegasys/artemis/datastructures/util/BeaconStateUtilTest.java index 96384296e02..2f51dde02a9 100644 --- a/ethereum/datastructures/src/test/java/tech/pegasys/artemis/datastructures/util/BeaconStateUtilTest.java +++ b/ethereum/datastructures/src/test/java/tech/pegasys/artemis/datastructures/util/BeaconStateUtilTest.java @@ -198,9 +198,9 @@ void getDomainReturnsAsExpectedForAllSignatureDomainTypesWithCurrentVersionFork( @Test void validateProofOfPosessionReturnsTrueIfTheBLSSignatureIsValidForGivenDepositInputData() { Deposit deposit = newDeposits(1).get(0); - BLSPublicKey pubkey = deposit.getDeposit_data().getDeposit_input().getPubkey(); + BLSPublicKey pubkey = deposit.getDeposit_data().getSignature().getPubkey(); BLSSignature proofOfPossession = - deposit.getDeposit_data().getDeposit_input().getProof_of_possession(); + deposit.getDeposit_data().getSignature().getProof_of_possession(); UnsignedLong domain = BeaconStateUtil.get_domain( new Fork( @@ -213,7 +213,7 @@ void validateProofOfPosessionReturnsTrueIfTheBLSSignatureIsValidForGivenDepositI assertTrue( BLSVerify.bls_verify( pubkey, - deposit.getDeposit_data().getDeposit_input().signed_root("proof_of_possession"), + deposit.getDeposit_data().getSignature().signed_root("proof_of_possession"), proofOfPossession, domain)); } @@ -223,7 +223,7 @@ void validateProofOfPosessionReturnsFalseIfTheBLSSignatureIsNotValidForGivenDepo Deposit deposit = newDeposits(1).get(0); BLSPublicKey pubkey = BLSPublicKey.random(); BLSSignature proofOfPossession = - deposit.getDeposit_data().getDeposit_input().getProof_of_possession(); + deposit.getDeposit_data().getSignature().getProof_of_possession(); UnsignedLong domain = BeaconStateUtil.get_domain( new Fork( @@ -236,7 +236,7 @@ void validateProofOfPosessionReturnsFalseIfTheBLSSignatureIsNotValidForGivenDepo assertFalse( BLSVerify.bls_verify( pubkey, - deposit.getDeposit_data().getDeposit_input().signed_root("proof_of_possession"), + deposit.getDeposit_data().getSignature().signed_root("proof_of_possession"), proofOfPossession, domain)); } @@ -245,7 +245,7 @@ void validateProofOfPosessionReturnsFalseIfTheBLSSignatureIsNotValidForGivenDepo void processDepositAddsNewValidatorWhenPubkeyIsNotFoundInRegistry() { // Data Setup Deposit deposit = newDeposits(1).get(0); - DepositInput depositInput = deposit.getDeposit_data().getDeposit_input(); + DepositInput depositInput = deposit.getDeposit_data().getSignature(); BLSPublicKey pubkey = depositInput.getPubkey(); Bytes32 withdrawalCredentials = depositInput.getWithdrawal_credentials(); UnsignedLong amount = deposit.getDeposit_data().getAmount(); @@ -281,7 +281,7 @@ void processDepositAddsNewValidatorWhenPubkeyIsNotFoundInRegistry() { void processDepositTopsUpValidatorBalanceWhenPubkeyIsFoundInRegistry() { // Data Setup Deposit deposit = newDeposits(1).get(0); - DepositInput depositInput = deposit.getDeposit_data().getDeposit_input(); + DepositInput depositInput = deposit.getDeposit_data().getSignature(); BLSPublicKey pubkey = depositInput.getPubkey(); Bytes32 withdrawalCredentials = depositInput.getWithdrawal_credentials(); UnsignedLong amount = deposit.getDeposit_data().getAmount(); diff --git a/ethereum/statetransition/src/main/java/tech/pegasys/artemis/statetransition/util/BlockProcessorUtil.java b/ethereum/statetransition/src/main/java/tech/pegasys/artemis/statetransition/util/BlockProcessorUtil.java index e7dcdb4a223..6e13b293161 100644 --- a/ethereum/statetransition/src/main/java/tech/pegasys/artemis/statetransition/util/BlockProcessorUtil.java +++ b/ethereum/statetransition/src/main/java/tech/pegasys/artemis/statetransition/util/BlockProcessorUtil.java @@ -372,7 +372,7 @@ public static void process_attestations(BeaconState state, BeaconBlock block) .getLatest_crosslinks() .get(toIntExact(attestation.getData().getShard().longValue())); checkArgument( - latest_crosslink.equals(attestation.getData().getPrevious_crosslink()) + latest_crosslink.equals(attestation.getData().getCrosslink()) || latest_crosslink.equals( new Crosslink( slot_to_epoch(attestationDataSlot), diff --git a/ethereum/statetransition/src/main/java/tech/pegasys/artemis/statetransition/util/EpochProcessorUtil.java b/ethereum/statetransition/src/main/java/tech/pegasys/artemis/statetransition/util/EpochProcessorUtil.java index 43c04ec2988..bccef9d1f8a 100644 --- a/ethereum/statetransition/src/main/java/tech/pegasys/artemis/statetransition/util/EpochProcessorUtil.java +++ b/ethereum/statetransition/src/main/java/tech/pegasys/artemis/statetransition/util/EpochProcessorUtil.java @@ -13,6 +13,37 @@ package tech.pegasys.artemis.statetransition.util; +import com.google.common.primitives.UnsignedLong; +import org.apache.commons.lang3.tuple.MutablePair; +import org.apache.logging.log4j.Level; +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; +import org.apache.tuweni.ssz.SSZ; +import tech.pegasys.artemis.datastructures.Constants; +import tech.pegasys.artemis.datastructures.blocks.Eth1DataVote; +import tech.pegasys.artemis.datastructures.operations.AttestationData; +import tech.pegasys.artemis.datastructures.state.BeaconState; +import tech.pegasys.artemis.datastructures.state.BeaconStateWithCache; +import tech.pegasys.artemis.datastructures.state.Crosslink; +import tech.pegasys.artemis.datastructures.state.CrosslinkCommittee; +import tech.pegasys.artemis.datastructures.state.HistoricalBatch; +import tech.pegasys.artemis.datastructures.state.PendingAttestation; +import tech.pegasys.artemis.datastructures.state.Validator; +import tech.pegasys.artemis.datastructures.util.BeaconStateUtil; +import tech.pegasys.artemis.util.alogger.ALogger; +import tech.pegasys.artemis.util.bitwise.BitwiseOps; +import tech.pegasys.artemis.util.hashtree.HashTreeUtil; +import tech.pegasys.artemis.util.hashtree.HashTreeUtil.SSZTypes; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + import static java.lang.Math.toIntExact; import static tech.pegasys.artemis.datastructures.Constants.ACTIVATION_EXIT_DELAY; import static tech.pegasys.artemis.datastructures.Constants.FAR_FUTURE_EPOCH; @@ -26,6 +57,7 @@ import static tech.pegasys.artemis.datastructures.util.BeaconStateUtil.generate_seed; import static tech.pegasys.artemis.datastructures.util.BeaconStateUtil.get_attestation_participants; import static tech.pegasys.artemis.datastructures.util.BeaconStateUtil.get_beacon_proposer_index; +import static tech.pegasys.artemis.datastructures.util.BeaconStateUtil.get_bitfield_bit; import static tech.pegasys.artemis.datastructures.util.BeaconStateUtil.get_block_root; import static tech.pegasys.artemis.datastructures.util.BeaconStateUtil.get_crosslink_committees_at_slot; import static tech.pegasys.artemis.datastructures.util.BeaconStateUtil.get_current_epoch; @@ -40,36 +72,9 @@ import static tech.pegasys.artemis.datastructures.util.BeaconStateUtil.min; import static tech.pegasys.artemis.datastructures.util.BeaconStateUtil.prepare_validator_for_withdrawal; import static tech.pegasys.artemis.datastructures.util.BeaconStateUtil.slot_to_epoch; +import static tech.pegasys.artemis.datastructures.util.BeaconStateUtil.verify_bitfield; import static tech.pegasys.artemis.datastructures.util.ValidatorsUtil.get_active_validator_indices; -import com.google.common.primitives.UnsignedLong; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.TreeSet; -import java.util.stream.Collectors; -import java.util.stream.IntStream; -import org.apache.commons.lang3.tuple.MutablePair; -import org.apache.logging.log4j.Level; -import org.apache.tuweni.bytes.Bytes32; -import org.apache.tuweni.ssz.SSZ; -import tech.pegasys.artemis.datastructures.Constants; -import tech.pegasys.artemis.datastructures.blocks.Eth1DataVote; -import tech.pegasys.artemis.datastructures.state.BeaconState; -import tech.pegasys.artemis.datastructures.state.BeaconStateWithCache; -import tech.pegasys.artemis.datastructures.state.Crosslink; -import tech.pegasys.artemis.datastructures.state.CrosslinkCommittee; -import tech.pegasys.artemis.datastructures.state.HistoricalBatch; -import tech.pegasys.artemis.datastructures.state.PendingAttestation; -import tech.pegasys.artemis.datastructures.state.Validator; -import tech.pegasys.artemis.datastructures.util.BeaconStateUtil; -import tech.pegasys.artemis.util.alogger.ALogger; -import tech.pegasys.artemis.util.bitwise.BitwiseOps; -import tech.pegasys.artemis.util.hashtree.HashTreeUtil; -import tech.pegasys.artemis.util.hashtree.HashTreeUtil.SSZTypes; - public final class EpochProcessorUtil { private static final ALogger LOG = new ALogger(EpochProcessorUtil.class.getName()); @@ -104,22 +109,6 @@ public static UnsignedLong get_previous_total_balance(BeaconState state) { } } - /** - * Returns the union of validator index sets, where the sets are the attestation participants of - * attestations passed in TODO: the union part takes O(n^2) time, where n is the number of - * validators. OPTIMIZE - */ - public static List get_attesting_indices( - BeaconState state, List attestations) throws IllegalArgumentException { - - TreeSet output = new TreeSet<>(); - for (PendingAttestation a : attestations) { - output.addAll(get_attestation_participants(state, a.getData(), a.getAggregation_bitfield())); - } - List output_list = new ArrayList<>(output); - return output_list; - } - /** * @param state * @param attestations @@ -192,13 +181,13 @@ public static MutablePair> get_winning_root_and_participa List valid_attestations = new ArrayList<>(); List all_roots = new ArrayList<>(); for (PendingAttestation a : state.getCurrent_epoch_attestations()) { - if (a.getData().getPrevious_crosslink().equals(shardLatestCrosslink)) { + if (a.getData().getCrosslink().equals(shardLatestCrosslink)) { valid_attestations.add(a); all_roots.add(a.getData().getCrosslink_data_root()); } } for (PendingAttestation a : state.getPrevious_epoch_attestations()) { - if (a.getData().getPrevious_crosslink().equals(shardLatestCrosslink)) { + if (a.getData().getCrosslink().equals(shardLatestCrosslink)) { valid_attestations.add(a); all_roots.add(a.getData().getCrosslink_data_root()); } diff --git a/util/src/main/java/tech/pegasys/artemis/util/hashtree/HashTreeUtil.java b/util/src/main/java/tech/pegasys/artemis/util/hashtree/HashTreeUtil.java index c0ee738741c..d7eafd86f86 100644 --- a/util/src/main/java/tech/pegasys/artemis/util/hashtree/HashTreeUtil.java +++ b/util/src/main/java/tech/pegasys/artemis/util/hashtree/HashTreeUtil.java @@ -254,8 +254,4 @@ private static Bytes32 mix_in_length(Bytes32 merkle_root, int length) { return Hash.keccak256( Bytes.concatenate(merkle_root, Bytes.ofUnsignedInt(length, LITTLE_ENDIAN))); } - - private static boolean is_power_of_two(int value) { - return value > 0 && (value & (value - 1)) == 0; - } }