-
Notifications
You must be signed in to change notification settings - Fork 211
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
Conversation
@dshulyak can you review this PR please? thank you |
e91d90c
to
68cbe07
Compare
bors try |
tryBuild succeeded: |
68cbe07
to
d183eb2
Compare
bors try |
tryBuild succeeded: |
blocks/certifier.go
Outdated
return nil | ||
} | ||
|
||
logger.WithFields(bid) |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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 | |||
} | |||
|
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
blocks/certifier.go
Outdated
|
||
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") |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
blocks/certifier.go
Outdated
logger.Error("layer not registered for cert") | ||
return unknown, errInternal | ||
} else if ci.bid != bid { | ||
logger.Error("block not registered for cert") |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
sql/layers/layers.go
Outdated
} | ||
} | ||
|
||
func prune(cert *types.Certificate) { |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
p2p/pubsub/pubsub.go
Outdated
@@ -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" |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shortened
blocks/certifier.go
Outdated
return nil | ||
} | ||
|
||
func (c *Certifier) tryGenCert() error { |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
blocks/certifier.go
Outdated
if _, ok := c.certMsgs[lid]; !ok { | ||
logger.Warning("layer not registered for cert") | ||
return unknown, errUnexpectedMsg | ||
} else if _, ok = c.certMsgs[lid][bid]; !ok { |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
blocks/certifier.go
Outdated
type CertConfig struct { | ||
CommitteeSize int | ||
CertifyThreshold int | ||
SignatureWaitDuration int |
There was a problem hiding this comment.
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
blocks/certifier.go
Outdated
|
||
c.certMsgs[lid][bid] = &certInfo{ | ||
deadline: now.Add(time.Duration(c.cfg.SignatureWaitDuration) * time.Second), | ||
signatures: make([]types.CertifyMessage, 0, c.cfg.CertifyThreshold), |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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):
go-spacemesh/blocks/certifier.go
Lines 340 to 351 in a526925
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.
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
okidoki
bors try |
tryBuild failed: |
There was a problem hiding this 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.
There was a problem hiding this 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
There was a problem hiding this 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
f02b690
to
bfb910b
Compare
bors try |
tryBuild succeeded: |
bors merge |
## 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
Pull request successfully merged into develop. Build succeeded: |
Motivation
Closes #3200
Part of #3199
Changes
layers
instead ofblocks
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.