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

[Merged by Bors] - block: generate certificate for hare output #3449

Closed
wants to merge 16 commits into from

Conversation

countvonzero
Copy link
Contributor

Motivation

Closes #3200
Part of #3199

Changes

  • certificate is saved in table layers instead of blocks because it's expected for hare to output empty block id for a layer, and that certifiers can certify an empty block id for a layer.
  • certifier waits till it has f+1 signatures and produce a certificate and save to db.
  • syncer fetches the certificate to use as hare output

@countvonzero countvonzero changed the title block: generate certifiable for hare output block: generate certificate for hare output Aug 16, 2022
@countvonzero
Copy link
Contributor Author

@dshulyak can you review this PR please? thank you

@countvonzero
Copy link
Contributor Author

bors try

bors bot added a commit that referenced this pull request Aug 16, 2022
@bors
Copy link

bors bot commented Aug 16, 2022

try

Build succeeded:

sql/migrations/0001_initial.sql Show resolved Hide resolved
common/types/block.go Show resolved Hide resolved
sql/layers/layers.go Show resolved Hide resolved
hare/haretypes.go Show resolved Hide resolved
fetch/layers.go Show resolved Hide resolved
blocks/certifier.go Outdated Show resolved Hide resolved
blocks/certifier.go Outdated Show resolved Hide resolved
blocks/certifier.go Show resolved Hide resolved
blocks/certifier.go Outdated Show resolved Hide resolved
blocks/certifier.go Outdated Show resolved Hide resolved
@countvonzero
Copy link
Contributor Author

bors try

bors bot added a commit that referenced this pull request Aug 17, 2022
@bors
Copy link

bors bot commented Aug 17, 2022

try

Build succeeded:

blocks/certifier.go Outdated Show resolved Hide resolved
return nil
}

logger.WithFields(bid)
Copy link
Contributor

Choose a reason for hiding this comment

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

logger = logger.WithFields(bid)
it looks like it always creates a new instance

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

@@ -166,3 +166,35 @@ type BlockContextualValidity struct {
ID BlockID
Validity bool
}

Copy link
Contributor

Choose a reason for hiding this comment

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

please call go generate on this file. you will need scalegen binary

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done


func (c *Certifier) getCertStateLocked(logger log.Log, lid types.LayerID, bid types.BlockID) (certState, error) {
if ci, ok := c.certMsgs[lid]; !ok {
logger.Error("layer not registered for cert")
Copy link
Contributor

Choose a reason for hiding this comment

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

this is expected if very old message is received for any reason, at most should be a warning
also why internal?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done.

logger.Error("layer not registered for cert")
return unknown, errInternal
} else if ci.bid != bid {
logger.Error("block not registered for cert")
Copy link
Contributor

Choose a reason for hiding this comment

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

some part of the committee can be malicious and will sign different block
we should collect certificates for all blocks, until one of the them has enough space units

Copy link
Contributor Author

Choose a reason for hiding this comment

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

changed code to allow for multiple blocks.

blocks/certifier.go Outdated Show resolved Hide resolved
}
}

func prune(cert *types.Certificate) {
Copy link
Contributor

Choose a reason for hiding this comment

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

not sure what was the idea but it doesn't prune stuff, it just zeroes it out

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yikes. changed to use new struct so the field is nil slice

Copy link
Contributor Author

Choose a reason for hiding this comment

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

hmmm... this doesn't matter. the BlockID is an array and so is still zeroed out values. will revert this.

sql/migrations/0001_initial.sql Show resolved Hide resolved
@@ -62,6 +62,9 @@ const (
// HareProtocol is the protocol id for hare messages.
HareProtocol = "/sm/hr/1"

// BlockCertify is the protocol id for block certification.
BlockCertify = "/sm/bc/1"
Copy link
Contributor

Choose a reason for hiding this comment

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

i should have paid more attention to the original change :)

we really should remove all useless stuff from this names, they will add bloat on the wire. for example /sm/ and third slash is not needed. so as long as they are unique we are good

Copy link
Contributor Author

Choose a reason for hiding this comment

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

shortened

return nil
}

func (c *Certifier) tryGenCert() error {
Copy link
Contributor

Choose a reason for hiding this comment

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

i don't understand the purpose of this method
certificate should be generatable when handler received sufficient number of messages to cross threshold

Copy link
Contributor Author

Choose a reason for hiding this comment

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

glad you caught me. it was meant to prune. but then i over did it. now it's just pruning old data.

if _, ok := c.certMsgs[lid]; !ok {
logger.Warning("layer not registered for cert")
return unknown, errUnexpectedMsg
} else if _, ok = c.certMsgs[lid][bid]; !ok {
Copy link
Contributor

Choose a reason for hiding this comment

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

so you won't be collecting certificates for blocks that this node didn't generate? i misunderstood it during initial review

so if for any reason (missing state/bugs) this node wasn't able to form full certificate - it will download it only from other peers

in this case it probably makes no sense to store a map with blocks

Copy link
Contributor Author

Choose a reason for hiding this comment

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

that's right. i had assume that you want me to write code such that the malicious nodes who are able to connect to all network splits can also use. i will revert back to single block assumption.

type CertConfig struct {
CommitteeSize int
CertifyThreshold int
SignatureWaitDuration int
Copy link
Contributor

Choose a reason for hiding this comment

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

better to use time.Duration and avoid multiplying it by time.Second later


c.certMsgs[lid][bid] = &certInfo{
deadline: now.Add(time.Duration(c.cfg.SignatureWaitDuration) * time.Second),
signatures: make([]types.CertifyMessage, 0, c.cfg.CertifyThreshold),
Copy link
Contributor

Choose a reason for hiding this comment

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

i believe this makes no difference now

Copy link
Contributor Author

Choose a reason for hiding this comment

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

not sure what you mean. do you mean it makes no difference what the capacity is?

Copy link
Contributor

@dshulyak dshulyak Aug 18, 2022

Choose a reason for hiding this comment

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

i meant that we don't expect number of signatures to be equal to this threshold. we expect eligibility count to be equal to threshold

Copy link
Contributor Author

Choose a reason for hiding this comment

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

right. but i still need to initialize it to some capacity, and given that we don't use fraction for eligibility count, this is a safe number to use. or the committee size.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, the CertifyThreshold is the maximum it can be. (i.e. everybody's signer's weight is 1)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

exactly why do you think this need work? this is the maximum capacity that can be possible. as such, no comments is required. adding unnecessary comments will only serve to confuse.

you yourself said

If it was enterprise software, I would have left it at CommitteeSize when I read it the first time.

please unblock. this is not cool. @jonZlotnik

Copy link
Contributor

Choose a reason for hiding this comment

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

I would have left it at CommitteeSize because it doesn't matter in enterprise software. You have your colleagues to explain things to you so I would have just ignored that it was too big an array for what it was. CommitteeSize makes it more confusing than CertifyThreshold

The maximum possible capacity that it would grow to is CertifyThreshold because if we assume every committee member has one eligibility, your implementation collects signatures until CertifyThreshold number of signatures is reached, and then builds/saves the certificate. It drops any further signatures (as it should):

func (c *Certifier) saveMessage(logger log.Log, msg types.CertifyMessage) error {
c.mu.Lock()
defer c.mu.Unlock()
lid := msg.LayerID
bid := msg.BlockID
if state, err := c.getCertStateLocked(logger, lid, bid); err != nil {
return err
} else if state != pending { // already certified
return nil
}

If any committee member has any more than 1 eligibility, the number of signatures required to reach CertifyThreshold decreases.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm okay with either:
make([]types.CertifyMessage, 0, c.cfg.CertifyThreshold)
or
make([]types.CertifyMessage, 0)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

my rationale is, committee size is the max size it can grow for any implementation. the current impl, the max is the threshold yes. but say we decided to wait for ALL msgs before we certify? and because it matters so little (800 vs 401), i decided to go for the future-safe one.

Copy link
Contributor

Choose a reason for hiding this comment

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

okidoki

@countvonzero
Copy link
Contributor Author

bors try

bors bot added a commit that referenced this pull request Aug 18, 2022
@bors
Copy link

bors bot commented Aug 18, 2022

try

Build failed:

fetch/layers.go Outdated Show resolved Hide resolved
blocks/certifier.go Outdated Show resolved Hide resolved
blocks/certifier.go Outdated Show resolved Hide resolved
blocks/certifier.go Show resolved Hide resolved
Copy link
Contributor

@jonZlotnik jonZlotnik left a comment

Choose a reason for hiding this comment

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

My last comments don't affect behavior.

Copy link
Contributor

@jonZlotnik jonZlotnik left a comment

Choose a reason for hiding this comment

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

I don't like circles

Copy link
Contributor

@jonZlotnik jonZlotnik left a comment

Choose a reason for hiding this comment

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

"do what's right and leave the consequences to code"
- some sticker, 2022

@countvonzero
Copy link
Contributor Author

bors try

bors bot added a commit that referenced this pull request Aug 19, 2022
@bors
Copy link

bors bot commented Aug 19, 2022

try

Build succeeded:

@countvonzero
Copy link
Contributor Author

bors merge

bors bot pushed a commit that referenced this pull request Aug 19, 2022
## Motivation
<!-- Please mention the issue fixed by this PR or detailed motivation -->
Closes #3200 
Part of #3199 

## Changes
<!-- Please describe in detail the changes made -->
- certificate is saved in table `layers` instead of `blocks` because it's expected for hare to output empty block id for a layer, and that certifiers can certify an empty block id for a layer.
- certifier waits till it has f+1 signatures and produce a certificate and save to db.
- syncer fetches the certificate to use as hare output
@bors
Copy link

bors bot commented Aug 19, 2022

Pull request successfully merged into develop.

Build succeeded:

@bors bors bot changed the title block: generate certificate for hare output [Merged by Bors] - block: generate certificate for hare output Aug 19, 2022
@bors bors bot closed this Aug 19, 2022
@bors bors bot deleted the certifiable-fraud branch August 19, 2022 20:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants