diff --git a/beacon-chain/blockchain/BUILD.bazel b/beacon-chain/blockchain/BUILD.bazel index 624c6c17c519..5ae652a02e5a 100644 --- a/beacon-chain/blockchain/BUILD.bazel +++ b/beacon-chain/blockchain/BUILD.bazel @@ -6,13 +6,11 @@ go_library( importpath = "github.com/prysmaticlabs/prysm/beacon-chain/blockchain", visibility = ["//beacon-chain:__subpackages__"], deps = [ + "//beacon-chain/core/blocks:go_default_library", "//beacon-chain/core/state:go_default_library", "//beacon-chain/core/types:go_default_library", - "//beacon-chain/core/validators:go_default_library", "//beacon-chain/db:go_default_library", "//beacon-chain/powchain:go_default_library", - "//beacon-chain/utils:go_default_library", - "//shared/bitutil:go_default_library", "//shared/event:go_default_library", "//shared/params:go_default_library", "@com_github_ethereum_go_ethereum//common:go_default_library", diff --git a/beacon-chain/blockchain/service.go b/beacon-chain/blockchain/service.go index 33a8d9466a41..6baa40acfd00 100644 --- a/beacon-chain/blockchain/service.go +++ b/beacon-chain/blockchain/service.go @@ -2,7 +2,6 @@ package blockchain import ( - "bytes" "context" "errors" "fmt" @@ -10,13 +9,12 @@ import ( "github.com/ethereum/go-ethereum/common" gethTypes "github.com/ethereum/go-ethereum/core/types" + b "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks" "github.com/prysmaticlabs/prysm/beacon-chain/core/state" + "github.com/prysmaticlabs/prysm/beacon-chain/core/types" - v "github.com/prysmaticlabs/prysm/beacon-chain/core/validators" "github.com/prysmaticlabs/prysm/beacon-chain/db" "github.com/prysmaticlabs/prysm/beacon-chain/powchain" - "github.com/prysmaticlabs/prysm/beacon-chain/utils" - "github.com/prysmaticlabs/prysm/shared/bitutil" "github.com/prysmaticlabs/prysm/shared/event" "github.com/prysmaticlabs/prysm/shared/params" "github.com/sirupsen/logrus" @@ -363,7 +361,7 @@ func (c *ChainService) isBlockReadyForProcessing(block *types.Block) bool { powBlockFetcher = c.web3Service.Client().BlockByHash } - if err := state.IsValidBlock(c.ctx, beaconState, block, c.enablePOWChain, + if err := b.IsValidBlock(c.ctx, beaconState, block, c.enablePOWChain, c.beaconDB.HasBlock, powBlockFetcher, c.genesisTime); err != nil { log.Debugf("block does not fulfill pre-processing conditions %v", err) return false @@ -381,168 +379,3 @@ func (c *ChainService) sendAndDeleteCachedBlocks(currentSlot uint64) { delete(c.unProcessedBlocks, currentSlot) } } - -// DEPRECATED: Will be replaced by new block processing method -func (c *ChainService) processBlockOld(block *types.Block) error { - blockHash, err := block.Hash() - if err != nil { - return fmt.Errorf("failed to get hash of block: %v", err) - } - - parent, err := c.beaconDB.GetBlock(block.ParentHash()) - if err != nil { - return fmt.Errorf("could not get parent block: %v", err) - } - if parent == nil { - return fmt.Errorf("block points to nil parent: %#x", block.ParentHash()) - } - - beaconState, err := c.beaconDB.GetState() - if err != nil { - return fmt.Errorf("failed to get beacon state: %v", err) - } - - if c.enablePOWChain && !c.doesPoWBlockExist(beaconState.ProcessedPowReceiptRootHash32()) { - return errors.New("proof-of-Work chain reference in block does not exist") - } - - // Verifies the block against the validity conditions specifies as part of the - // Ethereum 2.0 specification. - if err := state.IsValidBlockOld( - block, - beaconState, - parent.SlotNumber(), - c.genesisTime, - c.beaconDB.HasBlock, - ); err != nil { - return fmt.Errorf("block failed validity conditions: %v", err) - } - - if err := c.calculateNewBlockVotes(block, beaconState); err != nil { - return fmt.Errorf("failed to calculate block vote cache: %v", err) - } - - // First, include new attestations to the active state - // so that they're accounted for during cycle transitions. - beaconState.SetPendingAttestations(block.Attestations()) - - // If the block is valid, we compute its associated state tuple (active, crystallized) - beaconState, err = c.executeStateTransitionOld(beaconState, block, parent.SlotNumber()) - if err != nil { - return fmt.Errorf("initialize new cycle transition failed: %v", err) - } - - if err := c.beaconDB.SaveBlock(block); err != nil { - return fmt.Errorf("failed to save block: %v", err) - } - if err := c.beaconDB.SaveUnfinalizedBlockState(beaconState); err != nil { - return fmt.Errorf("error persisting unfinalized block's state: %v", err) - } - - log.WithField("hash", fmt.Sprintf("%#x", blockHash)).Info("Processed beacon block") - - // We keep a map of unfinalized blocks in memory along with their state - // pair to apply the fork choice rule. - c.unfinalizedBlocks[blockHash] = beaconState - - return nil -} - -// DEPRECATED: Will be removed soon -func (c *ChainService) executeStateTransitionOld( - beaconState *types.BeaconState, - block *types.Block, - parentSlot uint64, -) (*types.BeaconState, error) { - log.WithField("slotNumber", block.SlotNumber()).Info("Executing state transition") - blockVoteCache, err := c.beaconDB.ReadBlockVoteCache(beaconState.LatestBlockRootHashes32()) - if err != nil { - return nil, err - } - newState, err := state.NewStateTransition(beaconState, block, parentSlot, blockVoteCache) - if err != nil { - return nil, err - } - if newState.IsValidatorSetChange(block.SlotNumber()) { - log.WithField("slotNumber", block.SlotNumber()).Info("Validator set rotation occurred") - } - return newState, nil -} - -func (c *ChainService) calculateNewBlockVotes(block *types.Block, beaconState *types.BeaconState) error { - for _, attestation := range block.Attestations() { - parentHashes, err := beaconState.SignedParentHashes(block, attestation) - if err != nil { - return err - } - shardCommittees, err := v.GetShardAndCommitteesForSlot( - beaconState.ShardAndCommitteesForSlots(), - beaconState.LastStateRecalculationSlot(), - attestation.GetSlot(), - ) - if err != nil { - return fmt.Errorf("unable to fetch ShardAndCommittees for slot %d: %v", attestation.Slot, err) - } - attesterIndices, err := v.AttesterIndices(shardCommittees, attestation) - if err != nil { - return err - } - - // Read block vote cache from DB. - var blockVoteCache utils.BlockVoteCache - if blockVoteCache, err = c.beaconDB.ReadBlockVoteCache(parentHashes); err != nil { - return err - } - - // Update block vote cache. - for _, h := range parentHashes { - // Skip calculating for this hash if the hash is part of oblique parent hashes. - var skip bool - for _, oblique := range attestation.ObliqueParentHashes { - if bytes.Equal(h[:], oblique) { - skip = true - break - } - } - if skip { - continue - } - - // Initialize vote cache of a given block hash if it doesn't exist already. - if !blockVoteCache.IsVoteCacheExist(h) { - blockVoteCache[h] = utils.NewBlockVote() - } - - // Loop through attester indices, if the attester has voted but was not accounted for - // in the cache, then we add attester's index and balance to the block cache. - for i, attesterIndex := range attesterIndices { - var attesterExists bool - isBitSet, err := bitutil.CheckBit(attestation.AttesterBitfield, i) - if err != nil { - log.Errorf("Bitfield check for cache adding failed at index: %d with: %v", i, err) - } - - if !isBitSet { - continue - } - for _, indexInCache := range blockVoteCache[h].VoterIndices { - if attesterIndex == indexInCache { - attesterExists = true - break - } - } - if !attesterExists { - blockVoteCache[h].VoterIndices = append(blockVoteCache[h].VoterIndices, attesterIndex) - blockVoteCache[h].VoteTotalDeposit += beaconState.ValidatorRegistry()[attesterIndex].Balance - } - } - } - - // Write updated block vote cache back to DB. - if err = c.beaconDB.WriteBlockVoteCache(blockVoteCache); err != nil { - return err - } - } - - return nil -} diff --git a/beacon-chain/blockchain/service_test.go b/beacon-chain/blockchain/service_test.go index 1ba173f9b8a7..8c3f58b624ef 100644 --- a/beacon-chain/blockchain/service_test.go +++ b/beacon-chain/blockchain/service_test.go @@ -446,47 +446,3 @@ func TestIsBlockReadyForProcessing(t *testing.T) { } } - -func TestUpdateBlockVoteCache(t *testing.T) { - db := internal.SetupDB(t) - defer internal.TeardownDB(t, db) - chainService := setupBeaconChain(t, true, db) - - beaconState, err := types.NewGenesisBeaconState(nil) - if err != nil { - t.Fatalf("failed to initialize genesis state: %v", err) - } - block := types.NewBlock(&pb.BeaconBlock{ - Slot: 1, - ParentRootHash32: []byte{}, - Attestations: []*pb.AggregatedAttestation{ - { - Slot: 0, - Shard: 1, - AttesterBitfield: []byte{'F', 'F'}, - }, - }, - }) - - err = chainService.calculateNewBlockVotes(block, beaconState) - if err != nil { - t.Errorf("failed to update the block vote cache: %v", err) - } -} - -func TestUpdateBlockVoteCacheNoAttestations(t *testing.T) { - db := internal.SetupDB(t) - defer internal.TeardownDB(t, db) - chainService := setupBeaconChain(t, true, db) - - beaconState, err := types.NewGenesisBeaconState(nil) - if err != nil { - t.Fatalf("failed to initialize genesis state: %v", err) - } - block := types.NewBlock(nil) - - err = chainService.calculateNewBlockVotes(block, beaconState) - if err != nil { - t.Errorf("failed to update the block vote cache: %v", err) - } -} diff --git a/beacon-chain/core/blocks/BUILD.bazel b/beacon-chain/core/blocks/BUILD.bazel index 428978dc1e85..a5cea576a216 100644 --- a/beacon-chain/core/blocks/BUILD.bazel +++ b/beacon-chain/core/blocks/BUILD.bazel @@ -2,7 +2,10 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") go_library( name = "go_default_library", - srcs = ["block_operations.go"], + srcs = [ + "block_operations.go", + "validity_conditions.go", + ], importpath = "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks", visibility = ["//beacon-chain:__subpackages__"], deps = [ @@ -11,16 +14,25 @@ go_library( "//proto/beacon/p2p/v1:go_default_library", "//shared/params:go_default_library", "//shared/slices:go_default_library", + "@com_github_ethereum_go_ethereum//common:go_default_library", + "@com_github_ethereum_go_ethereum//core/types:go_default_library", ], ) go_test( name = "go_default_test", - srcs = ["block_operations_test.go"], + srcs = [ + "block_operations_test.go", + "validity_conditions_test.go", + ], embed = [":go_default_library"], deps = [ "//beacon-chain/core/types:go_default_library", + "//beacon-chain/utils:go_default_library", "//proto/beacon/p2p/v1:go_default_library", "//shared/params:go_default_library", + "@com_github_ethereum_go_ethereum//common:go_default_library", + "@com_github_ethereum_go_ethereum//core/types:go_default_library", + "@com_github_sirupsen_logrus//:go_default_library", ], ) diff --git a/beacon-chain/core/blocks/validity_conditions.go b/beacon-chain/core/blocks/validity_conditions.go new file mode 100644 index 000000000000..c054d6713d8d --- /dev/null +++ b/beacon-chain/core/blocks/validity_conditions.go @@ -0,0 +1,66 @@ +package blocks + +import ( + "context" + "fmt" + "time" + + "github.com/ethereum/go-ethereum/common" + gethTypes "github.com/ethereum/go-ethereum/core/types" + "github.com/prysmaticlabs/prysm/beacon-chain/core/types" +) + +// IsValidBlock ensures that the block is compliant with the block processing validity conditions. +// Spec: +// For a beacon chain block, block, to be processed by a node, the following conditions must be met: +// The parent block with root block.parent_root has been processed and accepted. +// The node has processed its state up to slot, block.slot - 1. +// The Ethereum 1.0 block pointed to by the state.processed_pow_receipt_root has been processed and accepted. +// The node's local clock time is greater than or equal to state.genesis_time + block.slot * SLOT_DURATION. +func IsValidBlock( + ctx context.Context, + state *types.BeaconState, + block *types.Block, + enablePOWChain bool, + HasBlock func(hash [32]byte) bool, + GetPOWBlock func(ctx context.Context, hash common.Hash) (*gethTypes.Block, error), + genesisTime time.Time) error { + + // Pre-Processing Condition 1: + // Check that the parent Block has been processed and saved. + parentBlock := HasBlock(block.ParentHash()) + if !parentBlock { + return fmt.Errorf("unprocessed parent block as it is not saved in the db: %#x", block.ParentHash()) + } + + // Pre-Processing Condition 2: + // The state is updated up to block.slot -1. + + if state.Slot() != block.SlotNumber()-1 { + return fmt.Errorf( + "block slot is not valid %d as it is supposed to be %d", block.SlotNumber(), state.Slot()+1) + } + + if enablePOWChain { + powBlock, err := GetPOWBlock(ctx, state.ProcessedPowReceiptRootHash32()) + if err != nil { + return fmt.Errorf("unable to retrieve POW chain reference block %v", err) + } + + // Pre-Processing Condition 3: + // The block pointed to by the state in state.processed_pow_receipt_root has + // been processed in the ETH 1.0 chain. + if powBlock == nil { + return fmt.Errorf("proof-of-Work chain reference in state does not exist %#x", state.ProcessedPowReceiptRootHash32()) + } + } + + // Pre-Processing Condition 4: + // The node's local time is greater than or equal to + // state.genesis_time + block.slot * SLOT_DURATION. + if !block.IsSlotValid(genesisTime) { + return fmt.Errorf("slot of block is too high: %d", block.SlotNumber()) + } + + return nil +} diff --git a/beacon-chain/core/blocks/validity_conditions_test.go b/beacon-chain/core/blocks/validity_conditions_test.go new file mode 100644 index 000000000000..12c9c3ba0ede --- /dev/null +++ b/beacon-chain/core/blocks/validity_conditions_test.go @@ -0,0 +1,123 @@ +package blocks + +import ( + "context" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common" + gethTypes "github.com/ethereum/go-ethereum/core/types" + "github.com/prysmaticlabs/prysm/beacon-chain/core/types" + "github.com/prysmaticlabs/prysm/beacon-chain/utils" + pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" + "github.com/prysmaticlabs/prysm/shared/params" + "github.com/sirupsen/logrus" +) + +func init() { + logrus.SetLevel(logrus.DebugLevel) +} + +type mockDB struct { + hasBlock bool + blockVoteCache utils.BlockVoteCache +} + +func (f *mockDB) HasBlock(h [32]byte) bool { + return f.hasBlock +} + +func (f *mockDB) ReadBlockVoteCache(blockHashes [][32]byte) (utils.BlockVoteCache, error) { + return f.blockVoteCache, nil +} + +type mockPOWClient struct { + blockExists bool +} + +func (m *mockPOWClient) BlockByHash(ctx context.Context, hash common.Hash) (*gethTypes.Block, error) { + if m.blockExists { + return &gethTypes.Block{}, nil + } + return nil, nil +} + +func TestBadBlock(t *testing.T) { + beaconState, err := types.NewGenesisBeaconState(nil) + if err != nil { + t.Fatalf("failed to generate beacon state: %v", err) + } + + ctx := context.Background() + + db := &mockDB{} + powClient := &mockPOWClient{} + + beaconState.SetSlot(3) + + block := types.NewBlock(&pb.BeaconBlock{ + Slot: 4, + }) + + genesisTime := params.BeaconConfig().GenesisTime + + db.hasBlock = false + + if err := IsValidBlock(ctx, beaconState, block, true, + db.HasBlock, powClient.BlockByHash, genesisTime); err == nil { + t.Fatal("block is valid despite not having a parent") + } + + block.Proto().Slot = 3 + db.hasBlock = true + + if err := IsValidBlock(ctx, beaconState, block, true, + db.HasBlock, powClient.BlockByHash, genesisTime); err == nil { + t.Fatalf("block is valid despite having an invalid slot %d", block.SlotNumber()) + } + + block.Proto().Slot = 4 + powClient.blockExists = false + + if err := IsValidBlock(ctx, beaconState, block, true, + db.HasBlock, powClient.BlockByHash, genesisTime); err == nil { + t.Fatalf("block is valid despite having an invalid pow reference block") + } + + invalidTime := time.Now().AddDate(1, 2, 3) + powClient.blockExists = false + + if err := IsValidBlock(ctx, beaconState, block, true, + db.HasBlock, powClient.BlockByHash, genesisTime); err == nil { + t.Fatalf("block is valid despite having an invalid genesis time %v", invalidTime) + } + +} + +func TestValidBlock(t *testing.T) { + beaconState, err := types.NewGenesisBeaconState(nil) + if err != nil { + t.Fatalf("failed to generate beacon state: %v", err) + } + + ctx := context.Background() + + db := &mockDB{} + powClient := &mockPOWClient{} + + beaconState.SetSlot(3) + db.hasBlock = true + + block := types.NewBlock(&pb.BeaconBlock{ + Slot: 4, + }) + + genesisTime := params.BeaconConfig().GenesisTime + powClient.blockExists = true + + if err := IsValidBlock(ctx, beaconState, block, true, + db.HasBlock, powClient.BlockByHash, genesisTime); err != nil { + t.Fatal(err) + } + +} diff --git a/beacon-chain/core/incentives/BUILD.bazel b/beacon-chain/core/incentives/BUILD.bazel index 84b1cc452feb..62204424d20b 100644 --- a/beacon-chain/core/incentives/BUILD.bazel +++ b/beacon-chain/core/incentives/BUILD.bazel @@ -6,10 +6,7 @@ go_library( importpath = "github.com/prysmaticlabs/prysm/beacon-chain/core/incentives", visibility = ["//beacon-chain:__subpackages__"], deps = [ - "//beacon-chain/core/validators:go_default_library", - "//beacon-chain/utils:go_default_library", "//proto/beacon/p2p/v1:go_default_library", - "//shared/bitutil:go_default_library", "//shared/mathutil:go_default_library", "//shared/params:go_default_library", ], diff --git a/beacon-chain/core/incentives/incentives.go b/beacon-chain/core/incentives/incentives.go index 0d583625107b..6f51cce25c81 100644 --- a/beacon-chain/core/incentives/incentives.go +++ b/beacon-chain/core/incentives/incentives.go @@ -5,137 +5,11 @@ package incentives import ( - v "github.com/prysmaticlabs/prysm/beacon-chain/core/validators" - "github.com/prysmaticlabs/prysm/beacon-chain/utils" pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" - "github.com/prysmaticlabs/prysm/shared/bitutil" "github.com/prysmaticlabs/prysm/shared/mathutil" "github.com/prysmaticlabs/prysm/shared/params" ) -// TallyVoteBalances calculates all the votes behind a block and -// then rewards validators for their participation in voting for that block. -func TallyVoteBalances( - blockHash [32]byte, - blockVoteCache utils.BlockVoteCache, - validators []*pb.ValidatorRecord, - activeValidatorIndices []uint32, - totalActiveValidatorDeposit uint64, - timeSinceFinality uint64, -) (uint64, []*pb.ValidatorRecord) { - blockVote, ok := blockVoteCache[blockHash] - if !ok { - return 0, validators - } - - blockVoteBalance := blockVote.VoteTotalDeposit - voterIndices := blockVote.VoterIndices - newValidatorRegistry := CalculateRewards( - voterIndices, - activeValidatorIndices, - validators, - totalActiveValidatorDeposit, - blockVoteBalance, - timeSinceFinality, - ) - - return blockVoteBalance, newValidatorRegistry -} - -// CalculateRewards adjusts validators balances by applying rewards or penalties -// based on FFG incentive structure. -// FFG Rewards scheme rewards validator who have voted on blocks, and penalises those validators -// who are offline. The penalties are more severe the longer they are offline. -func CalculateRewards( - voterIndices []uint32, - activeValidatorIndices []uint32, - validators []*pb.ValidatorRecord, - totalActiveValidatorDeposit uint64, - totalParticipatedDeposit uint64, - timeSinceFinality uint64, -) []*pb.ValidatorRecord { - - newValidatorSet := v.CopyValidatorRegistry(validators) - - // Calculate the reward and penalty quotients for the validator set. - rewardQuotient := RewardQuotient(totalActiveValidatorDeposit) - penaltyQuotient := QuadraticPenaltyQuotient() - - if timeSinceFinality <= 3*params.BeaconConfig().CycleLength { - for _, validatorIndex := range activeValidatorIndices { - var voted bool - - for _, voterIndex := range voterIndices { - if voterIndex == validatorIndex { - voted = true - balance := validators[validatorIndex].GetBalance() - newBalance := int64(balance) + int64(balance/rewardQuotient)*(2*int64(totalParticipatedDeposit)-int64(totalActiveValidatorDeposit))/int64(totalActiveValidatorDeposit) - newValidatorSet[validatorIndex].Balance = uint64(newBalance) - break - } - } - - if !voted { - newBalance := newValidatorSet[validatorIndex].GetBalance() - newBalance -= newBalance / rewardQuotient - newValidatorSet[validatorIndex].Balance = newBalance - } - } - - } else { - for _, validatorIndex := range activeValidatorIndices { - var voted bool - - for _, voterIndex := range voterIndices { - if voterIndex == validatorIndex { - voted = true - break - } - } - - if !voted { - newBalance := newValidatorSet[validatorIndex].GetBalance() - newBalance -= newBalance/rewardQuotient + newBalance*timeSinceFinality/penaltyQuotient - newValidatorSet[validatorIndex].Balance = newBalance - } - } - - } - - return newValidatorSet -} - -// ApplyCrosslinkRewardsAndPenalties applies the appropriate rewards and -// penalties according to the attestation for a shard. -func ApplyCrosslinkRewardsAndPenalties( - crosslinkRecords []*pb.CrosslinkRecord, - slot uint64, - attesterIndices []uint32, - attestation *pb.AggregatedAttestation, - validators []*pb.ValidatorRecord, - totalActiveValidatorDeposit uint64, - totalBalance uint64, - voteBalance uint64, -) ([]*pb.ValidatorRecord, error) { - newValidatorSet := v.CopyValidatorRegistry(validators) - - rewardQuotient := RewardQuotient(totalActiveValidatorDeposit) - for _, attesterIndex := range attesterIndices { - timeSinceLastConfirmation := slot - crosslinkRecords[attestation.Shard].GetSlot() - - checkBit, err := bitutil.CheckBit(attestation.AttesterBitfield, int(attesterIndex)) - if err != nil { - return nil, err - } - if checkBit { - newValidatorSet[attesterIndex] = RewardValidatorCrosslink(totalBalance, voteBalance, rewardQuotient, newValidatorSet[attesterIndex]) - } else { - newValidatorSet[attesterIndex] = PenaliseValidatorCrosslink(timeSinceLastConfirmation, rewardQuotient, newValidatorSet[attesterIndex]) - } - } - return newValidatorSet, nil -} - // RewardQuotient returns the reward quotient for validators which will be used to // reward validators for voting on blocks, or penalise them for being offline. func RewardQuotient(totalActiveValidatorDeposit uint64) uint64 { diff --git a/beacon-chain/core/incentives/incentives_test.go b/beacon-chain/core/incentives/incentives_test.go index ad149a4a01e7..bb579113c0f9 100644 --- a/beacon-chain/core/incentives/incentives_test.go +++ b/beacon-chain/core/incentives/incentives_test.go @@ -18,93 +18,6 @@ func newValidatorRegistry() []*pb.ValidatorRecord { return validators } -func TestComputeValidatorRewardsAndPenalties(t *testing.T) { - validators := newValidatorRegistry() - defaultBalance := uint64(32 * 1e9) - - participatedDeposit := 4 * defaultBalance - totalDeposit := 10 * defaultBalance - rewQuotient := RewardQuotient(totalDeposit) - penaltyQuotient := QuadraticPenaltyQuotient() - timeSinceFinality := uint64(5) - - data := &pb.BeaconState{ - ValidatorRegistry: validators, - ValidatorRegistryLastChangeSlot: 1, - JustifiedSlot: 4, - FinalizedSlot: 3, - } - - activeValidatorIndices := make([]uint32, 0, len(validators)) - for i, v := range validators { - if v.Status == pb.ValidatorRecord_ACTIVE { - activeValidatorIndices = append(activeValidatorIndices, uint32(i)) - } - } - - rewardedValidatorRegistry := CalculateRewards( - []uint32{2, 3, 6, 9}, - activeValidatorIndices, - data.ValidatorRegistry, - totalDeposit, - participatedDeposit, - timeSinceFinality, - ) - - expectedBalance := defaultBalance - defaultBalance/uint64(rewQuotient) - - if rewardedValidatorRegistry[0].Balance != expectedBalance { - t.Fatalf("validator balance not updated correctly: %d, %d", rewardedValidatorRegistry[0].Balance, expectedBalance) - } - - expectedBalance = uint64(int64(defaultBalance) + int64(defaultBalance/rewQuotient)*(2*int64(participatedDeposit)-int64(totalDeposit))/int64(totalDeposit)) - - if rewardedValidatorRegistry[6].Balance != expectedBalance { - t.Fatalf("validator balance not updated correctly: %d, %d", rewardedValidatorRegistry[6].Balance, expectedBalance) - } - - if rewardedValidatorRegistry[9].Balance != expectedBalance { - t.Fatalf("validator balance not updated correctly: %d, %d", rewardedValidatorRegistry[9].Balance, expectedBalance) - } - - validators = newValidatorRegistry() - timeSinceFinality = 200 - - activeValidatorIndices = make([]uint32, 0, len(validators)) - for i, v := range validators { - if v.Status == pb.ValidatorRecord_ACTIVE { - activeValidatorIndices = append(activeValidatorIndices, uint32(i)) - } - } - - rewardedValidatorRegistry = CalculateRewards( - []uint32{1, 2, 7, 8}, - activeValidatorIndices, - validators, - totalDeposit, - participatedDeposit, - timeSinceFinality) - - if rewardedValidatorRegistry[1].Balance != defaultBalance { - t.Fatalf("validator balance not updated correctly: %d, %d", rewardedValidatorRegistry[1].Balance, defaultBalance) - } - - if rewardedValidatorRegistry[7].Balance != defaultBalance { - t.Fatalf("validator balance not updated correctly: %d, %d", rewardedValidatorRegistry[7].Balance, defaultBalance) - } - - expectedBalance = defaultBalance - (defaultBalance/rewQuotient + defaultBalance*timeSinceFinality/penaltyQuotient) - - if rewardedValidatorRegistry[0].Balance != expectedBalance { - t.Fatalf("validator balance not updated correctly: %d, %d", rewardedValidatorRegistry[0].Balance, expectedBalance) - } - - if rewardedValidatorRegistry[9].Balance != expectedBalance { - t.Fatalf("validator balance not updated correctly: %d, %d", rewardedValidatorRegistry[9].Balance, expectedBalance) - } - -} - func TestRewardQuotient(t *testing.T) { defaultBalance := uint64(2 * 1e9) totalDeposit := defaultBalance diff --git a/beacon-chain/core/state/BUILD.bazel b/beacon-chain/core/state/BUILD.bazel index fb3857ee75bd..b2cbc109e0b3 100644 --- a/beacon-chain/core/state/BUILD.bazel +++ b/beacon-chain/core/state/BUILD.bazel @@ -2,46 +2,23 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") go_library( name = "go_default_library", - srcs = [ - "processing.go", - "state_transition.go", - "validity_conditions.go", - ], + srcs = ["state_transition.go"], importpath = "github.com/prysmaticlabs/prysm/beacon-chain/core/state", visibility = ["//beacon-chain:__subpackages__"], deps = [ - "//beacon-chain/core/incentives:go_default_library", "//beacon-chain/core/randao:go_default_library", "//beacon-chain/core/types:go_default_library", - "//beacon-chain/core/validators:go_default_library", - "//beacon-chain/utils:go_default_library", - "//proto/beacon/p2p/v1:go_default_library", - "//shared/bitutil:go_default_library", - "//shared/hashutil:go_default_library", "//shared/params:go_default_library", - "@com_github_ethereum_go_ethereum//common:go_default_library", - "@com_github_ethereum_go_ethereum//core/types:go_default_library", ], ) go_test( name = "go_default_test", - srcs = [ - "processing_test.go", - "state_transition_test.go", - "validity_conditions_test.go", - ], + srcs = ["state_transition_test.go"], embed = [":go_default_library"], deps = [ "//beacon-chain/core/types:go_default_library", - "//beacon-chain/core/validators:go_default_library", - "//beacon-chain/utils:go_default_library", "//proto/beacon/p2p/v1:go_default_library", - "//shared/bytes:go_default_library", - "//shared/hashutil:go_default_library", "//shared/params:go_default_library", - "@com_github_ethereum_go_ethereum//common:go_default_library", - "@com_github_ethereum_go_ethereum//core/types:go_default_library", - "@com_github_sirupsen_logrus//:go_default_library", ], ) diff --git a/beacon-chain/core/state/processing.go b/beacon-chain/core/state/processing.go deleted file mode 100644 index 1841efe60e7e..000000000000 --- a/beacon-chain/core/state/processing.go +++ /dev/null @@ -1,77 +0,0 @@ -package state - -import ( - "encoding/binary" - - "github.com/prysmaticlabs/prysm/beacon-chain/core/types" - v "github.com/prysmaticlabs/prysm/beacon-chain/core/validators" - pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" - "github.com/prysmaticlabs/prysm/shared/params" -) - -// FinalizeAndJustifySlots justifies slots and sets the justified streak according to Casper FFG -// conditions. It also finalizes slots when the conditions are fulfilled. -func FinalizeAndJustifySlots( - slot uint64, justifiedSlot uint64, finalizedSlot uint64, - justifiedStreak uint64, blockVoteBalance uint64, totalDeposits uint64) (uint64, uint64, uint64) { - cycleLength := params.BeaconConfig().CycleLength - - if 3*blockVoteBalance >= 2*totalDeposits { - if slot > justifiedSlot { - justifiedSlot = slot - } - justifiedStreak++ - } else { - justifiedStreak = 0 - } - - newFinalizedSlot := slot - cycleLength - 1 - - if slot > cycleLength && justifiedStreak >= cycleLength+1 && newFinalizedSlot > finalizedSlot { - finalizedSlot = newFinalizedSlot - } - - return justifiedSlot, finalizedSlot, justifiedStreak -} - -// UpdateLatestCrosslinks checks the vote balances and if there is a supermajority it sets the crosslink -// for that shard. -func UpdateLatestCrosslinks(slot uint64, voteBalance uint64, totalBalance uint64, - attestation *pb.AggregatedAttestation, crosslinkRecords []*pb.CrosslinkRecord) []*pb.CrosslinkRecord { - // if 2/3 of committee voted on this crosslink, update the crosslink - // with latest dynasty number, shard block hash, and slot number. - voteMajority := 3*voteBalance >= 2*totalBalance - if voteMajority { - crosslinkRecords[attestation.Shard] = &pb.CrosslinkRecord{ - ShardBlockRootHash32: attestation.ShardBlockHash, - Slot: slot, - } - } - return crosslinkRecords -} - -// ProcessSpecialRecords processes the pending special record objects, -// this is called during crystallized state transition. -func ProcessSpecialRecords(slotNumber uint64, validators []*pb.ValidatorRecord, - pendingSpecials []*pb.SpecialRecord) ([]*pb.ValidatorRecord, error) { - // For each special record object in active state. - for _, specialRecord := range pendingSpecials { - // Covers validators submitted logouts from last cycle. - if specialRecord.Kind == uint32(params.Logout) { - validatorIndex := binary.BigEndian.Uint64(specialRecord.Data[0]) - exitedValidator := v.ExitValidator(validators[validatorIndex], slotNumber, false) - validators[validatorIndex] = exitedValidator - // TODO(#633): Verify specialRecord.Data[1] as signature. - // BLSVerify(pubkey=validator.pubkey, msg=hash(LOGOUT_MESSAGE + bytes8(version)) - } - } - return validators, nil -} - -// ProcessBlock describes the per block operations that happen on every slot. -func ProcessBlock(state *types.BeaconState, block *types.Block) *types.BeaconState { - _ = block - // TODO(#1073): This function will encompass all the per block slot transition functions, this will - // contain checks for randao,proposer validity and block operations. - return state -} diff --git a/beacon-chain/core/state/processing_test.go b/beacon-chain/core/state/processing_test.go deleted file mode 100644 index c81c30320cb1..000000000000 --- a/beacon-chain/core/state/processing_test.go +++ /dev/null @@ -1,131 +0,0 @@ -package state - -import ( - "bytes" - "testing" - - pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" - b "github.com/prysmaticlabs/prysm/shared/bytes" - "github.com/prysmaticlabs/prysm/shared/params" -) - -func TestFinalizeAndJustifySlots(t *testing.T) { - slot := uint64(10) - justifiedSlot := uint64(8) - finalizedSlot := uint64(6) - justifiedStreak := uint64(2) - blockVoteBalance := uint64(2e9) - totalDeposit := uint64(4e9) - - justifiedSlot, finalizedSlot, justifiedStreak = FinalizeAndJustifySlots(slot, justifiedSlot, finalizedSlot, - justifiedStreak, blockVoteBalance, totalDeposit) - - if justifiedSlot != 8 { - t.Fatalf("justified slot has been updated %d", justifiedSlot) - } - - if justifiedStreak != 0 { - t.Fatalf("justified streak not updated %d", justifiedStreak) - } - - if finalizedSlot != 6 { - t.Fatalf("finalized slot changed when it was not supposed to %d", finalizedSlot) - } - - blockVoteBalance = uint64(3e9) - - justifiedSlot, finalizedSlot, justifiedStreak = FinalizeAndJustifySlots(slot, justifiedSlot, finalizedSlot, - justifiedStreak, blockVoteBalance, totalDeposit) - - if justifiedSlot != 10 { - t.Fatalf("justified slot has not been updated %d", justifiedSlot) - } - - if justifiedStreak != 1 { - t.Fatalf("justified streak not updated %d", justifiedStreak) - } - - if finalizedSlot != 6 { - t.Fatalf("finalized slot changed when it was not supposed to %d", finalizedSlot) - } - - slot = 100 - justifiedStreak = 70 - - justifiedSlot, finalizedSlot, justifiedStreak = FinalizeAndJustifySlots(slot, justifiedSlot, finalizedSlot, - justifiedStreak, blockVoteBalance, totalDeposit) - - if justifiedSlot != 100 { - t.Fatalf("justified slot has not been updated %d", justifiedSlot) - } - - if justifiedStreak != 71 { - t.Fatalf("justified streak not updated %d", justifiedStreak) - } - - if finalizedSlot == 6 { - t.Fatalf("finalized slot not updated when it was supposed to %d", finalizedSlot) - } - -} - -func TestLatestCrosslinks(t *testing.T) { - totalBalance := uint64(5e9) - voteBalance := uint64(4e9) - - crossLinks := []*pb.CrosslinkRecord{ - { - ShardBlockRootHash32: []byte{'A'}, - Slot: 10, - }, - { - ShardBlockRootHash32: []byte{'A'}, - Slot: 10, - }, - } - - attestation := &pb.AggregatedAttestation{ - Slot: 10, - Shard: 1, - ShardBlockHash: []byte{'B'}, - AttesterBitfield: []byte{100, 128, 8}, - } - - crossLinks = UpdateLatestCrosslinks(10, voteBalance, totalBalance, attestation, crossLinks) - crossLinks = UpdateLatestCrosslinks(10, voteBalance, totalBalance, attestation, crossLinks) - - if !bytes.Equal(crossLinks[1].GetShardBlockRootHash32(), []byte{'B'}) { - t.Errorf("shard blockhash not saved in crosslink record %v", crossLinks[1].GetShardBlockRootHash32()) - } - -} - -func TestProcessSpecialRecords(t *testing.T) { - - specialRecords := []*pb.SpecialRecord{ - {Kind: uint32(params.Logout), Data: [][]byte{b.Bytes8(4)}}, // Validator 4 - {Kind: uint32(params.Logout), Data: [][]byte{b.Bytes8(5)}}, // Validator 5 - } - - validators := make([]*pb.ValidatorRecord, 10) - for i := 0; i < len(validators); i++ { - validators[i] = &pb.ValidatorRecord{Status: pb.ValidatorRecord_ACTIVE} - } - - newValidatorRegistry, err := ProcessSpecialRecords(99, validators, specialRecords) - if err != nil { - t.Fatalf("Failed to call process special records %v", err) - } - if newValidatorRegistry[4].Status != pb.ValidatorRecord_ACTIVE_PENDING_EXIT { - t.Error("Validator 4 status is not PendingExit") - } - if newValidatorRegistry[4].LatestStatusChangeSlot != 99 { - t.Error("Validator 4 last status change slot is not 99") - } - if newValidatorRegistry[5].Status != pb.ValidatorRecord_ACTIVE_PENDING_EXIT { - t.Error("Validator 5 status is not PendingExit") - } - if newValidatorRegistry[5].LatestStatusChangeSlot != 99 { - t.Error("Validator 5 last status change slot is not 99") - } -} diff --git a/beacon-chain/core/state/state_transition.go b/beacon-chain/core/state/state_transition.go index 195d93cfe411..ab0e77e944af 100644 --- a/beacon-chain/core/state/state_transition.go +++ b/beacon-chain/core/state/state_transition.go @@ -3,128 +3,11 @@ package state import ( "fmt" - "github.com/ethereum/go-ethereum/common" - "github.com/prysmaticlabs/prysm/beacon-chain/core/incentives" "github.com/prysmaticlabs/prysm/beacon-chain/core/randao" "github.com/prysmaticlabs/prysm/beacon-chain/core/types" - v "github.com/prysmaticlabs/prysm/beacon-chain/core/validators" - "github.com/prysmaticlabs/prysm/beacon-chain/utils" - pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" "github.com/prysmaticlabs/prysm/shared/params" ) -// NewStateTransition computes the new beacon state. -// DEPRECATED: Will be removed soon. -// This function takes in the previous beacon stat, beacon block, and its parent slot. -// This method is called during a cycle transition. We also check for validator -// set change transition and compute for new committees if necessary during this transition. -func NewStateTransition( - st *types.BeaconState, - block *types.Block, - parentSlot uint64, - blockVoteCache utils.BlockVoteCache, -) (*types.BeaconState, error) { - var lastStateRecalculationSlotCycleBack uint64 - var err error - - newState := st.CopyState() - justifiedStreak := st.JustifiedStreak() - justifiedSlot := st.LastJustifiedSlot() - finalizedSlot := st.LastFinalizedSlot() - timeSinceFinality := block.SlotNumber() - newState.LastFinalizedSlot() - newState.SetValidatorRegistry(v.CopyValidatorRegistry(newState.ValidatorRegistry())) - - newState.ClearAttestations(st.LastStateRecalculationSlot()) - // Derive the new set of recent block hashes. - recentBlockHashes, err := st.CalculateNewBlockHashes(block, parentSlot) - if err != nil { - return nil, err - } - newState.SetLatestBlockHashes(recentBlockHashes) - if err != nil { - return nil, fmt.Errorf("failed to update recent block hashes: %v", err) - } - - newRandao := createRandaoMix(block.RandaoRevealHash32(), st.RandaoMix()) - newState.SetRandaoMix(newRandao[:]) - - // The changes below are only applied if this is a cycle transition. - if block.SlotNumber()%params.BeaconConfig().CycleLength == 0 { - if st.LastStateRecalculationSlot() < params.BeaconConfig().CycleLength { - lastStateRecalculationSlotCycleBack = 0 - } else { - lastStateRecalculationSlotCycleBack = st.LastStateRecalculationSlot() - params.BeaconConfig().CycleLength - } - - // walk through all the slots from LastStateRecalculationSlot - cycleLength to - // LastStateRecalculationSlot - 1. - for i := uint64(0); i < params.BeaconConfig().CycleLength; i++ { - var blockVoteBalance uint64 - - slot := lastStateRecalculationSlotCycleBack + i - blockHash := recentBlockHashes[i] - - blockVoteBalance, validators := incentives.TallyVoteBalances( - common.BytesToHash(blockHash), - blockVoteCache, - newState.ValidatorRegistry(), - v.ActiveValidatorIndices(newState.ValidatorRegistry()), - v.TotalActiveValidatorBalance(newState.ValidatorRegistry()), - timeSinceFinality, - ) - - newState.SetValidatorRegistry(validators) - - justifiedSlot, finalizedSlot, justifiedStreak = FinalizeAndJustifySlots( - slot, - justifiedSlot, - finalizedSlot, - justifiedStreak, - blockVoteBalance, - v.TotalActiveValidatorBalance(st.ValidatorRegistry()), - ) - } - - crossLinks, err := crossLinkCalculations( - newState, - st.PendingAttestations(), - block.SlotNumber(), - ) - if err != nil { - return nil, err - } - - newState.SetCrossLinks(crossLinks) - - newState.SetLastJustifiedSlot(justifiedSlot) - newState.SetLastFinalizedSlot(finalizedSlot) - newState.SetJustifiedStreak(justifiedStreak) - - // Exit the validators when their balance fall below min online deposit size. - newState.SetValidatorRegistry(v.CheckValidatorMinDeposit(newState.ValidatorRegistry(), block.SlotNumber())) - - // Entering new validator set change transition. - if newState.IsValidatorSetChange(block.SlotNumber()) { - newState.SetValidatorRegistryLastChangeSlot(newState.LastStateRecalculationSlot()) - shardAndCommitteesForSlots, err := validatorSetRecalculations( - newState.ShardAndCommitteesForSlots(), - newState.ValidatorRegistry(), - block.ParentHash(), - ) - if err != nil { - return nil, err - } - newState.SetShardAndCommitteesForSlots(shardAndCommitteesForSlots) - - period := block.SlotNumber() / params.BeaconConfig().MinWithdrawalPeriod - totalPenalties := newState.PenalizedETH(period) - newState.SetValidatorRegistry(v.ChangeValidatorRegistry(block.SlotNumber(), totalPenalties, newState.ValidatorRegistry())) - } - } - newState.SetLastStateRecalculationSlot(newState.LastStateRecalculationSlot() + 1) - return newState, nil -} - // ExecuteStateTransition defines the procedure for a state transition function. // Spec: // We now define the state transition function. At a high level the state transition is made up of two parts: @@ -168,91 +51,17 @@ func ExecuteStateTransition( return newState, nil } +// ProcessBlock describes the per block operations that happen on every slot. +func ProcessBlock(state *types.BeaconState, block *types.Block) *types.BeaconState { + _ = block + // TODO(#1073): This function will encompass all the per block slot transition functions, this will + // contain checks for randao,proposer validity and block operations. + return state +} + // NewEpochTransition describes the per epoch operations that are performed on the // beacon state. func NewEpochTransition(state *types.BeaconState) *types.BeaconState { // TODO(#1074): This will encompass all the related logic to epoch transitions. return state } - -// crossLinkCalculations checks if the proposed shard block has recevied -// 2/3 of the votes. If yes, we update crosslink record to point to -// the proposed shard block with latest beacon chain slot numbers. -func crossLinkCalculations( - st *types.BeaconState, - pendingAttestations []*pb.AggregatedAttestation, - currentSlot uint64, -) ([]*pb.CrosslinkRecord, error) { - slot := st.LastStateRecalculationSlot() + params.BeaconConfig().CycleLength - crossLinkRecords := st.LatestCrosslinks() - for _, attestation := range pendingAttestations { - shardCommittees, err := v.GetShardAndCommitteesForSlot( - st.ShardAndCommitteesForSlots(), - st.LastStateRecalculationSlot(), - attestation.GetSlot(), - ) - if err != nil { - return nil, err - } - - indices, err := v.AttesterIndices(shardCommittees, attestation) - if err != nil { - return nil, err - } - - totalBalance, voteBalance, err := v.VotedBalanceInAttestation(st.ValidatorRegistry(), indices, attestation) - if err != nil { - return nil, err - } - - newValidatorSet, err := incentives.ApplyCrosslinkRewardsAndPenalties( - crossLinkRecords, - currentSlot, - indices, - attestation, - st.ValidatorRegistry(), - v.TotalActiveValidatorBalance(st.ValidatorRegistry()), - totalBalance, - voteBalance, - ) - if err != nil { - return nil, err - } - st.SetValidatorRegistry(newValidatorSet) - crossLinkRecords = UpdateLatestCrosslinks(slot, voteBalance, totalBalance, attestation, crossLinkRecords) - } - return crossLinkRecords, nil -} - -// validatorSetRecalculation recomputes the validator set. -func validatorSetRecalculations( - shardAndCommittesForSlots []*pb.ShardAndCommitteeArray, - validators []*pb.ValidatorRecord, - seed [32]byte, -) ([]*pb.ShardAndCommitteeArray, error) { - lastSlot := len(shardAndCommittesForSlots) - 1 - lastCommitteeFromLastSlot := len(shardAndCommittesForSlots[lastSlot].ArrayShardAndCommittee) - 1 - crosslinkLastShard := shardAndCommittesForSlots[lastSlot].ArrayShardAndCommittee[lastCommitteeFromLastSlot].Shard - crosslinkNextShard := (crosslinkLastShard + 1) % params.BeaconConfig().ShardCount - - newShardCommitteeArray, err := v.ShuffleValidatorRegistryToCommittees( - seed, - validators, - crosslinkNextShard, - ) - if err != nil { - return nil, err - } - - return append(shardAndCommittesForSlots[params.BeaconConfig().CycleLength:], newShardCommitteeArray...), nil -} - -// createRandaoMix sets the block randao seed into a beacon state randao. This function -// XOR's the current state randao with the block's randao value added by the -// proposer. -func createRandaoMix(blockRandao [32]byte, beaconStateRandao [32]byte) [32]byte { - for i, b := range blockRandao { - beaconStateRandao[i] ^= b - } - return beaconStateRandao -} diff --git a/beacon-chain/core/state/state_transition_test.go b/beacon-chain/core/state/state_transition_test.go index ea6411859f40..3abb3780f08d 100644 --- a/beacon-chain/core/state/state_transition_test.go +++ b/beacon-chain/core/state/state_transition_test.go @@ -1,199 +1,13 @@ package state import ( - "bytes" - "strconv" "testing" "github.com/prysmaticlabs/prysm/beacon-chain/core/types" - v "github.com/prysmaticlabs/prysm/beacon-chain/core/validators" - "github.com/prysmaticlabs/prysm/beacon-chain/utils" pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" "github.com/prysmaticlabs/prysm/shared/params" ) -func TestInitialDeriveState(t *testing.T) { - beaconState, err := types.NewGenesisBeaconState(nil) - if err != nil { - t.Fatalf("Failed to initialize beacon state: %v", err) - } - - var attesterBitfield []byte - for uint64(len(attesterBitfield))*8 < params.BeaconConfig().BootstrappedValidatorsCount { - attesterBitfield = append(attesterBitfield, byte(0)) - } - - block := types.NewBlock(&pb.BeaconBlock{ - ParentRootHash32: []byte{'A'}, - Slot: 0, - StateRootHash32: []byte{}, - Attestations: []*pb.AggregatedAttestation{{ - Slot: 0, - AttesterBitfield: attesterBitfield, - Shard: 0, - }}, - }) - - var blockVoteCache utils.BlockVoteCache - newState, err := NewStateTransition(beaconState, block, 0, blockVoteCache) - if err != nil { - t.Fatalf("failed to derive new state: %v", err) - } - - if newState.LastJustifiedSlot() != 0 { - t.Fatalf("expected justified slot to equal %d: got %d", 0, newState.LastJustifiedSlot()) - } - - if newState.JustifiedStreak() != 0 { - t.Fatalf("expected justified streak to equal %d: got %d", 0, newState.JustifiedStreak()) - } - - if newState.LastStateRecalculationSlot() != 1 { - t.Fatalf("expected last state recalc to equal %d: got %d", 1, newState.LastStateRecalculationSlot()) - } - - if newState.LastFinalizedSlot() != 0 { - t.Fatalf("expected finalized slot to equal %d, got %d", 0, newState.LastFinalizedSlot()) - } -} - -func TestNextDeriveSlot(t *testing.T) { - beaconState, err := types.NewGenesisBeaconState(nil) - if err != nil { - t.Fatalf("Failed to initialized state: %v", err) - } - - block := types.NewBlock(&pb.BeaconBlock{ - ParentRootHash32: []byte{'A'}, - Slot: 0, - }) - - blockVoteCache := utils.NewBlockVoteCache() - beaconState, err = NewStateTransition(beaconState, block, 0, blockVoteCache) - if err != nil { - t.Fatalf("failed to derive next crystallized state: %v", err) - } - - beaconState.SetValidatorRegistry([]*pb.ValidatorRecord{ - {Balance: uint64(params.BeaconConfig().MaxDeposit * params.BeaconConfig().Gwei), - Status: pb.ValidatorRecord_ACTIVE}, - }) - - totalDeposits := v.TotalActiveValidatorBalance(beaconState.ValidatorRegistry()) - recentShardBlockHashes := make([][]byte, 3*params.BeaconConfig().CycleLength) - for i := 0; i < int(params.BeaconConfig().CycleLength); i++ { - shardBlockHash := [32]byte{} - counter := []byte(strconv.Itoa(i)) - copy(shardBlockHash[:], counter) - recentShardBlockHashes[i] = shardBlockHash[:] - blockVoteCache[shardBlockHash] = &utils.BlockVote{ - VoteTotalDeposit: totalDeposits * 3 / 4, - } - } - beaconState.SetLatestBlockHashes(recentShardBlockHashes) - beaconState.SetLastStateRecalculationSlot(params.BeaconConfig().CycleLength - 1) - block = types.NewBlock(&pb.BeaconBlock{ - ParentRootHash32: []byte{'A'}, - Slot: params.BeaconConfig().CycleLength, - }) - beaconState, err = NewStateTransition(beaconState, block, params.BeaconConfig().CycleLength, blockVoteCache) - if err != nil { - t.Fatalf("failed to derive state: %v", err) - } - if beaconState.LastStateRecalculationSlot() != params.BeaconConfig().CycleLength { - t.Fatalf("expected last state recalc to equal %d: got %d", params.BeaconConfig().CycleLength, beaconState.LastStateRecalculationSlot()) - } - if beaconState.LastJustifiedSlot() != params.BeaconConfig().CycleLength-1 { - t.Fatalf("expected justified slot to equal %d: got %d", params.BeaconConfig().CycleLength-1, beaconState.LastJustifiedSlot()) - } - if beaconState.JustifiedStreak() != params.BeaconConfig().CycleLength { - t.Fatalf("expected justified streak to equal %d: got %d", params.BeaconConfig().CycleLength, beaconState.JustifiedStreak()) - } - if beaconState.LastFinalizedSlot() != 0 { - t.Fatalf("expected finalized slot to equal %d: got %d", 0, beaconState.LastFinalizedSlot()) - } - - beaconState.SetLatestBlockHashes(recentShardBlockHashes) - beaconState.SetLastStateRecalculationSlot(2*params.BeaconConfig().CycleLength - 1) - block = types.NewBlock(&pb.BeaconBlock{ - ParentRootHash32: []byte{'A'}, - Slot: params.BeaconConfig().CycleLength * 2, - }) - beaconState, err = NewStateTransition(beaconState, block, params.BeaconConfig().CycleLength*2, blockVoteCache) - if err != nil { - t.Fatalf("failed to derive state: %v", err) - } - if beaconState.LastStateRecalculationSlot() != 2*params.BeaconConfig().CycleLength { - t.Fatalf("expected last state recalc to equal %d: got %d", 3, beaconState.LastStateRecalculationSlot()) - } - if beaconState.LastJustifiedSlot() != 2*(params.BeaconConfig().CycleLength-1) { - t.Fatalf("expected justified slot to equal %d: got %d", 2*params.BeaconConfig().CycleLength-1, beaconState.LastJustifiedSlot()) - } - if beaconState.JustifiedStreak() != 2*params.BeaconConfig().CycleLength { - t.Fatalf("expected justified streak to equal %d: got %d", 2*params.BeaconConfig().CycleLength, beaconState.JustifiedStreak()) - } - if beaconState.LastFinalizedSlot() != params.BeaconConfig().CycleLength-3 { - t.Fatalf("expected finalized slot to equal %d: got %d", params.BeaconConfig().CycleLength-2, beaconState.LastFinalizedSlot()) - } -} - -func TestProcessLatestCrosslinks(t *testing.T) { - // Set up crosslink record for every shard. - var clRecords []*pb.CrosslinkRecord - for i := uint64(0); i < params.BeaconConfig().ShardCount; i++ { - clRecord := &pb.CrosslinkRecord{ShardBlockRootHash32: []byte{'A'}, Slot: 1} - clRecords = append(clRecords, clRecord) - } - - // Set up validators. - var validators []*pb.ValidatorRecord - - for i := 0; i < 20; i++ { - validators = append(validators, &pb.ValidatorRecord{ - Balance: 1e18, - Status: pb.ValidatorRecord_ACTIVE, - }) - } - - // Set up pending attestations. - pAttestations := []*pb.AggregatedAttestation{ - { - Slot: 0, - Shard: 1, - ShardBlockHash: []byte{'a'}, - AttesterBitfield: []byte{224}, - }, - } - - // Process crosslinks happened at slot 50. - shardAndCommitteesForSlots, err := v.InitialShardAndCommitteesForSlots(validators) - if err != nil { - t.Fatalf("failed to initialize indices for slots: %v", err) - } - - committee := []uint32{0, 4, 6} - - shardAndCommitteesForSlots[0].ArrayShardAndCommittee[0].Committee = committee - - beaconState := types.NewBeaconState(&pb.BeaconState{ - LatestCrosslinks: clRecords, - ValidatorRegistry: validators, - ShardAndCommitteesForSlots: shardAndCommitteesForSlots, - }) - newLatestCrosslinks, err := crossLinkCalculations(beaconState, pAttestations, 100) - if err != nil { - t.Fatalf("process crosslink failed %v", err) - } - - if newLatestCrosslinks[1].Slot != params.BeaconConfig().CycleLength { - t.Errorf("Slot did not change for new cross link. Wanted: %d. Got: %d", params.BeaconConfig().CycleLength, newLatestCrosslinks[0].Slot) - } - if !bytes.Equal(newLatestCrosslinks[1].ShardBlockRootHash32, []byte{'a'}) { - t.Errorf("ShardBlockHash did not change for new cross link. Wanted a. Got: %s", newLatestCrosslinks[0].ShardBlockRootHash32) - } - //TODO(#538) Implement tests on balances of the validators in committee once big.Int is introduced. -} - func TestIsNewValidatorSetTransition(t *testing.T) { beaconState, err := types.NewGenesisBeaconState(nil) if err != nil { @@ -239,80 +53,3 @@ func TestIsNewValidatorSetTransition(t *testing.T) { t.Errorf("New validator set changen failed should have been true") } } - -func TestNewValidatorSetRecalculationsInvalid(t *testing.T) { - beaconState, err := types.NewGenesisBeaconState(nil) - if err != nil { - t.Fatalf("Failed to initialize state: %v", err) - } - // Negative test case, shuffle validators with more than MaxValidatorRegistry. - size := 1<<(params.BeaconConfig().RandBytes*8) - 1 - validators := make([]*pb.ValidatorRecord, size) - validator := &pb.ValidatorRecord{Status: pb.ValidatorRecord_ACTIVE} - for i := 0; i < size; i++ { - validators[i] = validator - } - beaconState.SetValidatorRegistry(validators) - if _, err := validatorSetRecalculations( - beaconState.ShardAndCommitteesForSlots(), - beaconState.ValidatorRegistry(), - [32]byte{'A'}, - ); err == nil { - t.Error("Validator set change calculation should have failed with invalid validator count") - } -} - -func TestNewValidatorSetRecalculations(t *testing.T) { - beaconState, err := types.NewGenesisBeaconState(nil) - if err != nil { - t.Fatalf("Failed to initialize state: %v", err) - } - - // Create shard committee for every slot. - var shardCommitteesForSlot []*pb.ShardAndCommitteeArray - for i := 0; i < int(params.BeaconConfig().CycleLength); i++ { - // Only 10 shards gets crosslinked by validators this period. - var shardCommittees []*pb.ShardAndCommittee - for i := 0; i < 10; i++ { - shardCommittees = append(shardCommittees, &pb.ShardAndCommittee{Shard: uint64(i)}) - } - shardCommitteesForSlot = append(shardCommitteesForSlot, &pb.ShardAndCommitteeArray{ArrayShardAndCommittee: shardCommittees}) - } - - beaconState.SetShardAndCommitteesForSlots(shardCommitteesForSlot) - beaconState.SetLastStateRecalculationSlot(65) - - _, err = validatorSetRecalculations( - beaconState.ShardAndCommitteesForSlots(), - beaconState.ValidatorRegistry(), - [32]byte{'A'}, - ) - if err != nil { - t.Fatalf("Validator set change failed %v", err) - } -} - -func TestPenalizedETH(t *testing.T) { - beaconState, err := types.NewGenesisBeaconState(nil) - if err != nil { - t.Fatalf("Failed to initialize state: %v", err) - } - beaconState.SetLatestPenalizedExitBalances([]uint64{100, 200, 300, 400, 500}) - beaconState.PenalizedETH(2) - - tests := []struct { - a uint64 - b uint64 - }{ - {a: 0, b: 100}, - {a: 1, b: 300}, - {a: 2, b: 600}, - {a: 3, b: 900}, - {a: 4, b: 1200}, - } - for _, tt := range tests { - if beaconState.PenalizedETH(tt.a) != tt.b { - t.Errorf("PenalizedETH(%d) = %v, want = %d", tt.a, beaconState.PenalizedETH(tt.a), tt.b) - } - } -} diff --git a/beacon-chain/core/state/validity_conditions.go b/beacon-chain/core/state/validity_conditions.go deleted file mode 100644 index 79d34a20e973..000000000000 --- a/beacon-chain/core/state/validity_conditions.go +++ /dev/null @@ -1,242 +0,0 @@ -package state - -import ( - "bytes" - "context" - "errors" - "fmt" - "time" - - "github.com/ethereum/go-ethereum/common" - gethTypes "github.com/ethereum/go-ethereum/core/types" - "github.com/prysmaticlabs/prysm/beacon-chain/core/types" - v "github.com/prysmaticlabs/prysm/beacon-chain/core/validators" - pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" - "github.com/prysmaticlabs/prysm/shared/bitutil" - "github.com/prysmaticlabs/prysm/shared/hashutil" - "github.com/prysmaticlabs/prysm/shared/params" -) - -// IsValidBlockOld checks the validity conditions of a block. -// DEPRECATED: Will be removed soon. -func IsValidBlockOld( - block *types.Block, - beaconState *types.BeaconState, - parentSlot uint64, - genesisTime time.Time, - isInChain func(blockHash [32]byte) bool, -) error { - _, err := block.Hash() - if err != nil { - return fmt.Errorf("could not hash incoming block: %v", err) - } - - if block.SlotNumber() == 0 { - return errors.New("cannot process a genesis block: received block with slot 0") - } - - if !block.IsSlotValid(genesisTime) { - return fmt.Errorf("slot of block is too high: %d", block.SlotNumber()) - } - - if err := doesParentProposerExist(block, beaconState, parentSlot); err != nil { - return fmt.Errorf("could not get proposer index: %v", err) - } - - for _, attestation := range block.Attestations() { - if err := isBlockAttestationValid(block, attestation, beaconState, parentSlot, isInChain); err != nil { - return fmt.Errorf("invalid block attestation: %v", err) - } - } - - _, proposerIndex, err := v.ProposerShardAndIndex( - beaconState.ShardAndCommitteesForSlots(), - beaconState.LastStateRecalculationSlot(), - block.SlotNumber(), - ) - if err != nil { - return fmt.Errorf("could not get proposer index: %v", err) - } - - stateProposerRandaoSeed := beaconState.ValidatorRegistry()[proposerIndex].RandaoCommitmentHash32 - blockRandaoRevealHash32 := block.RandaoRevealHash32() - - // If this is a block created by the simulator service (while in development - // mode), we skip the RANDAO validation condition. - isSimulatedBlock := bytes.Equal(blockRandaoRevealHash32[:], params.BeaconConfig().SimulatedBlockRandao[:]) - if !isSimulatedBlock && !block.IsRandaoValid(stateProposerRandaoSeed) { - return fmt.Errorf( - "pre-image of %#x is %#x, Got: %#x", - blockRandaoRevealHash32[:], - hashutil.Hash(blockRandaoRevealHash32[:]), - stateProposerRandaoSeed, - ) - } - return nil -} - -// IsValidBlock ensures that the block is compliant with the block processing validity conditions. -// Spec: -// For a beacon chain block, block, to be processed by a node, the following conditions must be met: -// The parent block with root block.parent_root has been processed and accepted. -// The node has processed its state up to slot, block.slot - 1. -// The Ethereum 1.0 block pointed to by the state.processed_pow_receipt_root has been processed and accepted. -// The node's local clock time is greater than or equal to state.genesis_time + block.slot * SLOT_DURATION. -func IsValidBlock( - ctx context.Context, - state *types.BeaconState, - block *types.Block, - enablePOWChain bool, - HasBlock func(hash [32]byte) bool, - GetPOWBlock func(ctx context.Context, hash common.Hash) (*gethTypes.Block, error), - genesisTime time.Time) error { - - // Pre-Processing Condition 1: - // Check that the parent Block has been processed and saved. - parentBlock := HasBlock(block.ParentHash()) - if !parentBlock { - return fmt.Errorf("unprocessed parent block as it is not saved in the db: %#x", block.ParentHash()) - } - - // Pre-Processing Condition 2: - // The state is updated up to block.slot -1. - - if state.Slot() != block.SlotNumber()-1 { - return fmt.Errorf( - "block slot is not valid %d as it is supposed to be %d", block.SlotNumber(), state.Slot()+1) - } - - if enablePOWChain { - powBlock, err := GetPOWBlock(ctx, state.ProcessedPowReceiptRootHash32()) - if err != nil { - return fmt.Errorf("unable to retrieve POW chain reference block %v", err) - } - - // Pre-Processing Condition 3: - // The block pointed to by the state in state.processed_pow_receipt_root has - // been processed in the ETH 1.0 chain. - if powBlock == nil { - return fmt.Errorf("proof-of-Work chain reference in state does not exist %#x", state.ProcessedPowReceiptRootHash32()) - } - } - - // Pre-Processing Condition 4: - // The node's local time is greater than or equal to - // state.genesis_time + block.slot * SLOT_DURATION. - if !block.IsSlotValid(genesisTime) { - return fmt.Errorf("slot of block is too high: %d", block.SlotNumber()) - } - - return nil -} - -// doesParentProposerExist checks that the proposer from the parent slot is included in the first -// aggregated attestation object -func doesParentProposerExist(block *types.Block, beaconState *types.BeaconState, parentSlot uint64) error { - _, parentProposerIndex, err := v.ProposerShardAndIndex( - beaconState.ShardAndCommitteesForSlots(), - beaconState.LastStateRecalculationSlot(), - parentSlot, - ) - if err != nil { - return err - } - - // Verifies the attester bitfield to check if the proposer index is in the first included one. - if isBitSet, err := bitutil.CheckBit(block.Attestations()[0].AttesterBitfield, int(parentProposerIndex)); !isBitSet { - return fmt.Errorf("could not locate proposer in the first attestation of AttestionRecord: %v", err) - } - return nil -} - -// isBlockAttestationValid verifies a block's attestations pass validity conditions. -// TODO(#781): Refactor with the new spec attestation checking conditions. -func isBlockAttestationValid( - block *types.Block, - attestation *pb.AggregatedAttestation, - beaconState *types.BeaconState, - parentSlot uint64, - isInChain func(blockHash [32]byte) bool, -) error { - // Validate attestation's slot number has is within range of incoming block number. - if err := isAttestationSlotNumberValid(attestation.Slot, parentSlot); err != nil { - return fmt.Errorf("invalid attestation slot %d: %v", attestation.Slot, err) - } - - if attestation.JustifiedSlot > beaconState.LastJustifiedSlot() { - return fmt.Errorf( - "attestation's justified slot has to be <= the state's last justified slot: found: %d. want <=: %d", - attestation.JustifiedSlot, - beaconState.LastJustifiedSlot(), - ) - } - - hash := [32]byte{} - copy(hash[:], attestation.JustifiedBlockHash) - if !isInChain(hash) { - return fmt.Errorf( - "the attestation's justifed block hash not found in current chain: justified block hash: 0x%x", - attestation.JustifiedBlockHash, - ) - } - - // Get all the block hashes up to cycle length. - parentHashes, err := beaconState.SignedParentHashes(block, attestation) - if err != nil { - return fmt.Errorf("unable to get signed parent hashes: %v", err) - } - - shardCommittees, err := v.GetShardAndCommitteesForSlot( - beaconState.ShardAndCommitteesForSlots(), - beaconState.LastStateRecalculationSlot(), - attestation.Slot, - ) - attesterIndices, err := v.AttesterIndices(shardCommittees, attestation) - if err != nil { - return fmt.Errorf("unable to get validator committee: %v", err) - } - - // Verify attester bitfields matches crystallized state's prev computed bitfield. - if !v.AreAttesterBitfieldsValid(attestation, attesterIndices) { - return fmt.Errorf("unable to match attester bitfield with shard and committee bitfield") - } - - // TODO(#258): Add coverage for determining fork version for an attestation. - forkData := beaconState.ForkData() - forkVersion := forkData.PostForkVersion - if attestation.Slot < forkData.ForkSlot { - forkVersion = forkData.PreForkVersion - } - - // TODO(#258): Generate validators aggregated pub key. - attestationMsg := types.AttestationMsg( - parentHashes, - attestation.ShardBlockHash, - attestation.Slot, - attestation.Shard, - attestation.JustifiedSlot, - forkVersion, - ) - _ = attestationMsg - - // TODO(#258): Verify msgHash against aggregated pub key and aggregated signature. - return nil -} - -func isAttestationSlotNumberValid(attestationSlot uint64, parentSlot uint64) error { - if parentSlot != 0 && attestationSlot > parentSlot { - return fmt.Errorf( - "attestation slot number higher than parent block's slot number: found: %d, needed < %d", - attestationSlot, - parentSlot, - ) - } - if parentSlot >= params.BeaconConfig().CycleLength-1 && attestationSlot < parentSlot-params.BeaconConfig().CycleLength+1 { - return fmt.Errorf( - "attestation slot number lower than parent block's slot number by one CycleLength: found: %d, needed > %d", - attestationSlot, - parentSlot-params.BeaconConfig().CycleLength+1, - ) - } - return nil -} diff --git a/beacon-chain/core/state/validity_conditions_test.go b/beacon-chain/core/state/validity_conditions_test.go deleted file mode 100644 index be08b7ef537a..000000000000 --- a/beacon-chain/core/state/validity_conditions_test.go +++ /dev/null @@ -1,256 +0,0 @@ -package state - -import ( - "context" - "testing" - "time" - - "github.com/ethereum/go-ethereum/common" - gethTypes "github.com/ethereum/go-ethereum/core/types" - "github.com/prysmaticlabs/prysm/beacon-chain/core/types" - "github.com/prysmaticlabs/prysm/beacon-chain/utils" - pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" - "github.com/prysmaticlabs/prysm/shared/hashutil" - "github.com/prysmaticlabs/prysm/shared/params" - "github.com/sirupsen/logrus" -) - -func init() { - logrus.SetLevel(logrus.DebugLevel) -} - -type mockDB struct { - hasBlock bool - blockVoteCache utils.BlockVoteCache -} - -func (f *mockDB) HasBlock(h [32]byte) bool { - return f.hasBlock -} - -func (f *mockDB) ReadBlockVoteCache(blockHashes [][32]byte) (utils.BlockVoteCache, error) { - return f.blockVoteCache, nil -} - -type mockPOWClient struct { - blockExists bool -} - -func (m *mockPOWClient) BlockByHash(ctx context.Context, hash common.Hash) (*gethTypes.Block, error) { - if m.blockExists { - return &gethTypes.Block{}, nil - } - return nil, nil -} - -func TestBadBlock(t *testing.T) { - beaconState, err := types.NewGenesisBeaconState(nil) - if err != nil { - t.Fatalf("failed to generate beacon state: %v", err) - } - - ctx := context.Background() - - db := &mockDB{} - powClient := &mockPOWClient{} - - beaconState.SetSlot(3) - - block := types.NewBlock(&pb.BeaconBlock{ - Slot: 4, - }) - - genesisTime := params.BeaconConfig().GenesisTime - - db.hasBlock = false - - if err := IsValidBlock(ctx, beaconState, block, true, - db.HasBlock, powClient.BlockByHash, genesisTime); err == nil { - t.Fatal("block is valid despite not having a parent") - } - - block.Proto().Slot = 3 - db.hasBlock = true - - if err := IsValidBlock(ctx, beaconState, block, true, - db.HasBlock, powClient.BlockByHash, genesisTime); err == nil { - t.Fatalf("block is valid despite having an invalid slot %d", block.SlotNumber()) - } - - block.Proto().Slot = 4 - powClient.blockExists = false - - if err := IsValidBlock(ctx, beaconState, block, true, - db.HasBlock, powClient.BlockByHash, genesisTime); err == nil { - t.Fatalf("block is valid despite having an invalid pow reference block") - } - - invalidTime := time.Now().AddDate(1, 2, 3) - powClient.blockExists = false - - if err := IsValidBlock(ctx, beaconState, block, true, - db.HasBlock, powClient.BlockByHash, genesisTime); err == nil { - t.Fatalf("block is valid despite having an invalid genesis time %v", invalidTime) - } - -} - -func TestValidBlock(t *testing.T) { - beaconState, err := types.NewGenesisBeaconState(nil) - if err != nil { - t.Fatalf("failed to generate beacon state: %v", err) - } - - ctx := context.Background() - - db := &mockDB{} - powClient := &mockPOWClient{} - - beaconState.SetSlot(3) - db.hasBlock = true - - block := types.NewBlock(&pb.BeaconBlock{ - Slot: 4, - }) - - genesisTime := params.BeaconConfig().GenesisTime - powClient.blockExists = true - - if err := IsValidBlock(ctx, beaconState, block, true, - db.HasBlock, powClient.BlockByHash, genesisTime); err != nil { - t.Fatal(err) - } - -} - -func TestBlockValidity(t *testing.T) { - beaconState, err := types.NewGenesisBeaconState(nil) - if err != nil { - t.Fatalf("failed to generate beacon state: %v", err) - } - - recentBlockHashes := make([][]byte, 2*params.BeaconConfig().CycleLength) - for i := 0; i < 2*int(params.BeaconConfig().CycleLength); i++ { - recentBlockHashes = append(recentBlockHashes, make([]byte, 32)) - } - randaoPreCommit := [32]byte{'A'} - hashedRandaoPreCommit := hashutil.Hash(randaoPreCommit[:]) - validators := beaconState.ValidatorRegistry() - validators[1].RandaoCommitmentHash32 = hashedRandaoPreCommit[:] - beaconState.SetValidatorRegistry(validators) - beaconState.SetLatestBlockHashes(recentBlockHashes) - - b := types.NewBlock(&pb.BeaconBlock{ - Slot: 1, - RandaoRevealHash32: randaoPreCommit[:], - Attestations: []*pb.AggregatedAttestation{ - { - Slot: 0, - Shard: 1, - JustifiedSlot: 0, - AttesterBitfield: []byte{128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - }, - }, - }) - - parentSlot := uint64(0) - db := &mockDB{} - db.hasBlock = true - - genesisTime := params.BeaconConfig().GenesisTime - if err := IsValidBlockOld(b, beaconState, parentSlot, genesisTime, db.HasBlock); err != nil { - t.Fatalf("failed block validation: %v", err) - } -} - -func TestBlockValidityNoParentProposer(t *testing.T) { - beaconState, err := types.NewGenesisBeaconState(nil) - if err != nil { - t.Fatalf("failed to generate beacon state: %v", err) - } - - recentBlockHashes := make([][]byte, 2*params.BeaconConfig().CycleLength) - for i := 0; i < 2*int(params.BeaconConfig().CycleLength); i++ { - recentBlockHashes = append(recentBlockHashes, make([]byte, 32)) - } - - beaconState.SetLatestBlockHashes(recentBlockHashes) - - parentSlot := uint64(1) - db := &mockDB{} - db.hasBlock = true - - // Test case with invalid RANDAO reveal. - badRandaoBlock := types.NewBlock(&pb.BeaconBlock{ - Slot: 2, - RandaoRevealHash32: []byte{'B'}, - Attestations: []*pb.AggregatedAttestation{ - { - Slot: 0, - Shard: 1, - JustifiedSlot: 0, - AttesterBitfield: []byte{64, 0}, - }, - }, - }) - genesisTime := params.BeaconConfig().GenesisTime - if err := IsValidBlockOld(badRandaoBlock, beaconState, parentSlot, genesisTime, db.HasBlock); err == nil { - t.Fatal("test should have failed without a parent proposer") - } -} - -func TestBlockValidityInvalidRandao(t *testing.T) { - beaconState, err := types.NewGenesisBeaconState(nil) - if err != nil { - t.Fatalf("failed to generate beacon state: %v", err) - } - - recentBlockHashes := make([][]byte, 2*params.BeaconConfig().CycleLength) - for i := 0; i < 2*int(params.BeaconConfig().CycleLength); i++ { - recentBlockHashes = append(recentBlockHashes, make([]byte, 32)) - } - - beaconState.SetLatestBlockHashes(recentBlockHashes) - - parentSlot := uint64(0) - db := &mockDB{} - db.hasBlock = true - - // Test case with invalid RANDAO reveal. - badRandaoBlock := types.NewBlock(&pb.BeaconBlock{ - Slot: 1, - RandaoRevealHash32: []byte{'B'}, - Attestations: []*pb.AggregatedAttestation{ - { - Slot: 0, - Shard: 1, - JustifiedSlot: 0, - AttesterBitfield: []byte{64, 0}, - }, - }, - }) - - genesisTime := params.BeaconConfig().GenesisTime - if err := IsValidBlockOld(badRandaoBlock, beaconState, parentSlot, genesisTime, db.HasBlock); err == nil { - t.Fatal("should have failed with invalid RANDAO") - } -} - -func TestIsAttestationSlotNumberValid(t *testing.T) { - if err := isAttestationSlotNumberValid(2, 1); err == nil { - t.Error("attestation slot number can't be higher than parent block's slot number") - } - - if err := isAttestationSlotNumberValid(1, params.BeaconConfig().CycleLength+1); err == nil { - t.Error("attestation slot number can't be lower than parent block's slot number by one CycleLength and 1") - } - - if err := isAttestationSlotNumberValid(2, 2); err != nil { - t.Errorf("attestation slot number could be less than or equal to parent block's slot number: %v", err) - } - - if err := isAttestationSlotNumberValid(2, 10); err != nil { - t.Errorf("attestation slot number could be less than or equal to parent block's slot number: %v", err) - } -} diff --git a/beacon-chain/core/types/state.go b/beacon-chain/core/types/state.go index 9daf595e6a23..3e2d56b3761e 100644 --- a/beacon-chain/core/types/state.go +++ b/beacon-chain/core/types/state.go @@ -1,8 +1,6 @@ package types import ( - "fmt" - "github.com/ethereum/go-ethereum/common" "github.com/gogo/protobuf/proto" v "github.com/prysmaticlabs/prysm/beacon-chain/core/validators" @@ -354,47 +352,6 @@ func (b *BeaconState) RandaoMix() [32]byte { return h } -// PenalizedETH calculates penalized total ETH during the last 3 withdrawal periods. -func (b *BeaconState) PenalizedETH(period uint64) uint64 { - var totalPenalty uint64 - penalties := b.LatestPenalizedExitBalances() - totalPenalty += getPenaltyForPeriod(penalties, period) - - if period >= 1 { - totalPenalty += getPenaltyForPeriod(penalties, period-1) - } - - if period >= 2 { - totalPenalty += getPenaltyForPeriod(penalties, period-2) - } - - return totalPenalty -} - -// SignedParentHashes returns all the parent hashes stored in active state up to last cycle length. -func (b *BeaconState) SignedParentHashes(block *Block, attestation *pb.AggregatedAttestation) ([][32]byte, error) { - latestBlockHashes := b.LatestBlockRootHashes32() - obliqueParentHashes := attestation.ObliqueParentHashes - earliestSlot := int(block.SlotNumber()) - len(latestBlockHashes) - - startIdx := int(attestation.Slot) - earliestSlot - int(params.BeaconConfig().CycleLength) + 1 - endIdx := startIdx - len(attestation.ObliqueParentHashes) + int(params.BeaconConfig().CycleLength) - if startIdx < 0 || endIdx > len(latestBlockHashes) || endIdx <= startIdx { - return nil, fmt.Errorf("attempt to fetch recent blockhashes from %d to %d invalid", startIdx, endIdx) - } - - hashes := make([][32]byte, 0, params.BeaconConfig().CycleLength) - for i := startIdx; i < endIdx; i++ { - hashes = append(hashes, latestBlockHashes[i]) - } - - for i := 0; i < len(obliqueParentHashes); i++ { - hash := common.BytesToHash(obliqueParentHashes[i]) - hashes = append(hashes, hash) - } - return hashes, nil -} - // ClearAttestations removes attestations older than last state recalc slot. func (b *BeaconState) ClearAttestations(lastStateRecalc uint64) { existing := b.data.PendingAttestations @@ -575,12 +532,3 @@ func (b *BeaconState) SetForkData(data *pb.ForkData) { func (b *BeaconState) SetSlot(slot uint64) { b.data.Slot = slot } - -func getPenaltyForPeriod(penalties []uint64, period uint64) uint64 { - numPeriods := uint64(len(penalties)) - if numPeriods < period+1 { - return 0 - } - - return penalties[period] -} diff --git a/beacon-chain/core/types/state_test.go b/beacon-chain/core/types/state_test.go index 7de98092048a..7e580f05e07a 100644 --- a/beacon-chain/core/types/state_test.go +++ b/beacon-chain/core/types/state_test.go @@ -204,102 +204,3 @@ func areBytesEqual(s1, s2 []byte) bool { } return true } - -func TestGetSignedParentHashes(t *testing.T) { - // Test the scenario described in the spec: - // https://github.com/ethereum/eth2.0-specs/blob/d7458bf201c8fcb93503272c8844381962488cb7/specs/beacon-chain.md#per-block-processing - cfg := params.BeaconConfig() - oldCycleLength := cfg.CycleLength - cycleLength := uint64(4) - cfg.CycleLength = cycleLength - defer func() { - cfg.CycleLength = oldCycleLength - }() - - blockHashes := make([][]byte, 11) - blockHashes[0] = createHashFromByte('Z') - blockHashes[1] = createHashFromByte('A') - blockHashes[2] = createHashFromByte('B') - blockHashes[3] = createHashFromByte('C') - blockHashes[4] = createHashFromByte('D') - blockHashes[5] = createHashFromByte('E') - blockHashes[6] = createHashFromByte('F') - blockHashes[7] = createHashFromByte('G') - blockHashes[8] = createHashFromByte('H') - blockHashes[9] = createHashFromByte('I') - blockHashes[10] = createHashFromByte('J') - - state := NewBeaconState(&pb.BeaconState{LatestBlockRootHash32S: blockHashes}) - - b := NewBlock(&pb.BeaconBlock{Slot: 11}) - - obliqueParentHashes := make([][]byte, 2) - obliqueParentHashes[0] = createHashFromByte(0) - obliqueParentHashes[1] = createHashFromByte(1) - a := &pb.AggregatedAttestation{ - ObliqueParentHashes: obliqueParentHashes, - Slot: 5, - } - - hashes, err := state.SignedParentHashes(b, a) - if err != nil { - t.Fatalf("failed to SignedParentHashes: %v", err) - } - if hashes[0][0] != 'B' || hashes[1][0] != 'C' { - t.Fatalf("SignedParentHashes did not return expected value: %#x and %#x", hashes[0], hashes[1]) - } - if hashes[2][0] != 0 || hashes[3][0] != 1 { - t.Fatalf("SignedParentHashes did not return expected value: %#x and %#x", hashes[0], hashes[1]) - } -} - -func TestGetSignedParentHashesIndexFail(t *testing.T) { - cfg := params.BeaconConfig() - oldCycleLength := cfg.CycleLength - cycleLength := uint64(4) - cfg.CycleLength = cycleLength - defer func() { - cfg.CycleLength = oldCycleLength - }() - - blockHashes := make([][]byte, 8) - blockHashes[0] = createHashFromByte('Z') - blockHashes[1] = createHashFromByte('A') - blockHashes[2] = createHashFromByte('B') - blockHashes[3] = createHashFromByte('C') - blockHashes[4] = createHashFromByte('D') - blockHashes[5] = createHashFromByte('E') - blockHashes[6] = createHashFromByte('F') - blockHashes[7] = createHashFromByte('G') - - state := NewBeaconState(&pb.BeaconState{LatestBlockRootHash32S: blockHashes}) - - b := NewBlock(&pb.BeaconBlock{Slot: 8}) - a := &pb.AggregatedAttestation{ - ObliqueParentHashes: [][]byte{}, - Slot: 2, - } - - _, err := state.SignedParentHashes(b, a) - if err == nil { - t.Error("expected SignedParentHashes to fail") - } - - a2 := &pb.AggregatedAttestation{ - ObliqueParentHashes: [][]byte{}, - Slot: 9, - } - _, err = state.SignedParentHashes(b, a2) - if err == nil { - t.Error("expected SignedParentHashes to fail") - } -} - -func createHashFromByte(repeatedByte byte) []byte { - hash := make([]byte, 32) - for i := 0; i < 32; i++ { - hash[i] = repeatedByte - } - - return hash -}