Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Part 3 of Aligning Beacon Chain with Latest 2.1 - Processing Attestations #423

Merged
merged 25 commits into from
Aug 24, 2018
Merged

Part 3 of Aligning Beacon Chain with Latest 2.1 - Processing Attestations #423

merged 25 commits into from
Aug 24, 2018

Conversation

terencechain
Copy link
Member

@terencechain terencechain commented Aug 21, 2018

Background

The primary load on beacon chain is attestations. To process an attestation means to attest parent block of the beacon chain, or attest block hash of the shard chain. Every beacon node has the responsibility to process all the attestations coming from a beacon block. That's how it calculates active and crystallized state.

Design

This PR implements the processAttestation inside processBlock function. Here's todos:

  • Remove checks for active and crystallized state roots. It was invalid, we are suppose to compute new state hashes, not compare with existing canonical state hashes
  • Verify AttestationRecord slot number is less than current block number and greater than block number that's one CYCLE_LENGTH before
  • Compute parent hashes based on active state's recent block hash array and oblique parent hashes from block
  • Get attestation indices that match the correct shard ID
  • Verify attester bitfield from AttestationRecord is the same length as attestation indices
  • Hash the following message hash((slot % CYCLE_LENGTH).to_bytes(8, 'big') + parent_hashes + shard_id + shard_block_hash)
  • Test and coverages

@terencechain terencechain self-assigned this Aug 21, 2018
@terencechain terencechain changed the title Part 2 of Aligning Core Package with Latest 2.1 - Processing Attestations Part 3 of Aligning Core Package with Latest 2.1 - Processing Attestations Aug 21, 2018
@codecov
Copy link

codecov bot commented Aug 21, 2018

Codecov Report

Merging #423 into master will increase coverage by 2.55%.
The diff coverage is 94.28%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #423      +/-   ##
==========================================
+ Coverage   73.67%   76.23%   +2.55%     
==========================================
  Files           7       35      +28     
  Lines         680     2188    +1508     
==========================================
+ Hits          501     1668    +1167     
- Misses        112      366     +254     
- Partials       67      154      +87
Impacted Files Coverage Δ
beacon-chain/node/node.go 58.97% <ø> (ø) ⬆️
beacon-chain/blockchain/service.go 70.37% <0%> (-0.88%) ⬇️
beacon-chain/types/block.go 93.54% <0%> (ø)
beacon-chain/utils/checkbit.go 100% <100%> (ø)
beacon-chain/casper/validator.go 100% <100%> (ø) ⬆️
validator/beacon/service.go 100% <100%> (ø)
validator/node/node.go 40.21% <100%> (ø)
beacon-chain/blockchain/core.go 75.55% <100%> (+5.49%) ⬆️
beacon-chain/casper/incentives.go 100% <100%> (+7.69%) ⬆️
... and 28 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 2ee9ec2...490bf84. Read the comment docs.

return signedParentHashes
}

// getAttestatorIndices returns the attestor committee of based from attestation's shard ID and slot number.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getAttesterIndices*


// Get all the block hashes up to cycle length.
parentHashes := b.getSignedParentHashes(block, attestation)
attesterIndices, err := b.getAttestatorIndices(attestation)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

b.getAttesterIndices 😛

lastBit := len(attesterIndices)
if lastBit%8 != 0 {
for i := 0; i < 8-lastBit%8; i++ {
voted, err := utils.CheckBit(attestation.AttesterBitfield, lastBit+i)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we simplify checkBit not to return an error? It seems reasonable that an out of index bit would return false since the bit at that index is not 1. The error seems unecessary IMO and it would make this method easier to use.

@@ -153,6 +153,9 @@ func (c *ChainService) ProcessBlock(block *types.Block) error {
return nil
}
if canProcess {
if err := c.chain.processAttestations(block); err != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This branch is untested. Can we add a test to ensure the attestations are processed on a block when canProcess is truthy?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Added TestProcessingBlockWithAttestations in blockchain's service_test.go

}
for _, tt := range tests {
if BitLength(tt.a) != tt.b {
t.Errorf("Expected %v, Got %v", tt.b, BitLength(tt.b))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great use of test driven tests. One improvement you could make is to structure this error message format to include the method name

t.Errorf("BitLength(%d) = %d, want = %d", tt.a, BitLength(tt.a), tt.b) 

Copy link
Member

@nisdas nisdas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

len(attestation.AttesterBitfield), utils.BitLength(len(attesterIndices)))
}

// Validate attestation can not have non-zero trailing bits.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/validate/valid/ ??

return nil, fmt.Errorf("can not return attester set of given height, input height %v has to be in between %v and %v", height, sback, sback+params.CycleLength*2)
// getBlockHash returns the block hash of a slot.
func (b *BeaconChain) getBlockHash(slot uint64, block *types.Block) ([]byte, error) {
sback := int(block.SlotNumber()) - params.CycleLength*2
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does sback mean?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

slot back. getBlockHash can only return within a range of block.Slot - 128 <= slot < block.Slot. Let's say current block is 200, but you wanna get the block hash of slot 50. That won't work because the further you can get is 200 - 128. And that is slot back

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will change sback to slotBack

// getBlockHash returns the block hash of a slot.
func (b *BeaconChain) getBlockHash(slot uint64, block *types.Block) ([]byte, error) {
sback := int(block.SlotNumber()) - params.CycleLength*2
if !(sback <= int(slot) && int(slot) < sback+params.CycleLength*2) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please change sback+params.CycleLength*2 to int(block.SlotNumber())

// Validate attestation can not have non-zero trailing bits.
lastBit := len(attesterIndices)
if lastBit%8 != 0 {
for i := 0; i < 8-lastBit%8; i++ {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don’t understand this logic. If length is 9, then it would only run check the first bit?

Copy link
Member Author

@terencechain terencechain Aug 23, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly. Let's say attester_bitfield is initialized in with attester_bitfield = (len(attestation_indices) + 7) // 8 empty bytes. So if committee_indices size is 10, attester_bitfield is 2 bytes, but the meaningful bits are still the left 10 bits. This checking from the spec is for keeping the padding bits clean.

@@ -146,13 +146,17 @@ func (c *ChainService) ProcessBlock(block *types.Block) error {
} else {
canProcess, err = c.chain.CanProcessBlock(nil, block, false)
}
fmt.Println(err)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove

@terencechain terencechain changed the title Part 3 of Aligning Core Package with Latest 2.1 - Processing Attestations Part 3 of Aligning Beacon Chain with Latest 2.1 - Processing Attestations Aug 24, 2018
@terencechain terencechain merged commit 1598ae8 into prysmaticlabs:master Aug 24, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants