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

Refactor common STR verification functionality #170

Merged
merged 47 commits into from
Sep 1, 2017
Merged

Conversation

masomel
Copy link
Member

@masomel masomel commented Mar 12, 2017

Since the client and auditor both need to perform some common consistency checks on the STRs, all this functionality should be refactored into a generic auditor module. This will also require the implementation of STR verification over a range of epochs.

See #155 (comment)

@masomel masomel added this to the 0.2.0 milestone Mar 12, 2017
@vqhuy vqhuy mentioned this pull request Mar 13, 2017
3 tasks
@liamsi
Copy link
Member

liamsi commented Apr 6, 2017

We will merge #155 first

@masomel masomel mentioned this pull request Jun 3, 2017
2 tasks
vqhuy added a commit that referenced this pull request Jun 8, 2017
// FIXME: check whether the STR was issued on time and whatnot.
// Maybe it has something to do w/ #81 and client transitioning between epochs.
// Try to verify w/ what's been saved

Copy link
Member

Choose a reason for hiding this comment

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

I think we should add a FIXME:

	// FIXME: we are returning the error immediately
	// without saving the inconsistent STR
	// see: https://github.com/coniks-sys/coniks-go/pull/74#commitcomment-19804686

here or in AuditDirectory.

Copy link
Member Author

Choose a reason for hiding this comment

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

Why is this a FIXME? Why should we be saving inconsistent STRs?

Copy link
Member

Choose a reason for hiding this comment

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

This makes me think we should do:

Any STR that passes the checks in updateSTR will be stored and used by the client, regardless of whether the rest of the checks pass / fail, and that's fine since it contains proof of being issued.

I think we should have a TODO/FIXME here so we can come back later, when we address client recovery & whistle-blowing issues.

Copy link
Member Author

Choose a reason for hiding this comment

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

I generally agree with this, but I think auditors should save inconsistent STRs in a separate list. I also agree that this is a whistleblowing and recovery issue. We should open a new issue for this if we don't have one already.

Copy link
Member

Choose a reason for hiding this comment

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

We have #87 and #171. What I was saying is we add a TODO here so we don't forget it.

// or the appropriate consistency check error if any of the checks fail,
// or str's epoch is anything other than the same or one ahead of
// a.verifiedSTR.
func (a *AudState) checkSTRAgainstVerified(str *DirSTR) error {
Copy link
Member

@vqhuy vqhuy Jul 19, 2017

Choose a reason for hiding this comment

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

Please reorder these functions as:

compareWithVerified()
verifySTRConsistency()
checkSTRAgainstVerified()
verifySTRRange()

// the given prevSTR and the first STR in the given range, and
// then verifies the consistency between each subsequent STR pair.
func (a *AudState) verifySTRRange(prevSTR *DirSTR, strs []*DirSTR) error {

Copy link
Member

Choose a reason for hiding this comment

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

Nitpicking: can we remove this empty line? Here and some other places.

if str == nil {
// FIXME: if this comes from the auditor, this
// should really be an ErrMalformedAuditorMessage
return ErrMalformedDirectoryMessage
Copy link
Member

Choose a reason for hiding this comment

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

I also encountered this problem, and I think we should just change this error and ErrMalformedClientMessage to ErrMalformedResquest and ErrMalformedResponse.

Copy link
Member

Choose a reason for hiding this comment

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

I can open a separate pull later, since I already have this.

Copy link
Member Author

Choose a reason for hiding this comment

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

Sounds good to me.

@@ -45,18 +43,48 @@ func NewCC(savedSTR *DirSTR, useTBs bool, signKey sign.PublicKey) *ConsistencyCh
if !useTBs {
panic("[coniks] Currently the server is forced to use TBs")
}
aud := NewAuditor(signKey, savedSTR)
cc := &ConsistencyChecks{
Copy link
Member

@vqhuy vqhuy Jul 19, 2017

Choose a reason for hiding this comment

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

It is easier for readers when we use field:value initializers.

Copy link
Member Author

Choose a reason for hiding this comment

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

I agree. This isn't currently consistent in all of the code, so we should fix this everywhere.

// the cc.verifiedSTR.
// CheckEquivocation() is called when a client receives a response to a
// message.AuditingRequest from an auditor.
func (cc *ConsistencyChecks) CheckEquivocation(msg *Response) error {
Copy link
Member

Choose a reason for hiding this comment

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

IMHO, we should open a separate pull for this feature, since I think we should cover something like the number of chosen auditors, and design a set of APIs for the /protocol level.

Copy link
Member Author

Choose a reason for hiding this comment

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

The number of chosen auditors is independent of the core equivocation check protocol -- that's what this is. What other APIs do we need for equivocation checking on the client?

Copy link
Member

Choose a reason for hiding this comment

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

How about taking an array of auditors' Response and passing them to CheckEquivocation? I have no strong opinion about this, though.

Copy link
Member Author

Choose a reason for hiding this comment

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

I thought about doing this, although that I think that already imposes a requirement on the client to check multiple auditors. I think that detail should be implemented at the application layer to make the use of auditors more flexible in the client.

@vqhuy
Copy link
Member

vqhuy commented Jul 19, 2017

If it's possible, please remove the empty line after the function name.
Please update the documentation in the comments (some function names are uppercase, or not matched with the new name).

signKey sign.PublicKey
snapshots map[uint64]*DirSTR
latestSTR *DirSTR
snapshots []*DirSTR
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 keep using the map as before? Is there any advantages over using a map?
I'm afraid that we may accidentally insert 2 same DirSTR into snapshots if we use slice.

Copy link
Member Author

Choose a reason for hiding this comment

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

This is a possibility, but the slice makes it much easier to append a whole batch of STRs. I wanted to avoid having to loop through a range twice, once for the verification, and one for the insertion into snapshots. But maybe this wouldn't be a huge performance issue?

Copy link
Member

Choose a reason for hiding this comment

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

Looking at current code, there are insertion and search operations, which are O(1), so I think it wouldn't be a huge performance issue.

Copy link
Member Author

Choose a reason for hiding this comment

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

Also addressing this as part of #182

// TODO: if the auditor has returned a more recent STR,
// should the client update its savedSTR? Should this
// force a new round of monitoring?
return cc.checkSTRAgainstVerified(LatestSTRInRange(strs.STR))
Copy link
Member

Choose a reason for hiding this comment

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

Last-minute nitpicking: should we remove LatestSTRInRange and just do

latestSTRInRange := strs[len(strs)-1]
return cc.checkSTRAgainstVerified(latestSTRInRange)

?
(or even pass strs[len(strs)-1] directly to checkSTRAgainstVerified)

Copy link
Member Author

Choose a reason for hiding this comment

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

LatestSTRInRange is only used here, right? I added this when I using a slice for the snapshots instead of a map, but it's no longer necessary now. I'll remove it.

// range if the message contains more than one STR.
// AuditDirectory() returns the appropriate consistency check error
// if any of the checks fail, or nil if the checks pass.
func (a *AudState) AuditDirectory(strs []*DirSTR) error {
Copy link
Member

Choose a reason for hiding this comment

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

@masomel @arlolra @liamsi Should we check null parameters in the function or assume that the caller will validate the parameters before calling?

Copy link
Member Author

Choose a reason for hiding this comment

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

Hmm, I generally assume that the caller hasn't validated the parameters. In the case of AuditDirectory, both ConsistencyChecks and AuditLog, both will call it inside of Audit, so in that case I think it would be safe to assume that the caller did a validation beforehand. OTOH, adding a parameter validation here is trivial, so I think we can add it here to be safe.


// Auditor provides a generic interface allowing different
// auditor types to implement specific auditing functionality.
type Auditor interface {
Copy link
Member

Choose a reason for hiding this comment

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

Maybe we should add a TODO "this interface is used nowhere, we should use it everywhere in ConsistencyChecks and AuditLog instead of AudState." ?

Copy link
Member Author

@masomel masomel Aug 11, 2017

Choose a reason for hiding this comment

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

I agree that ConsistencyChecks and AuditLog should "extend" Auditor rather than AudState, but to me this problem is more about how we can express what we mean.

Ideally, what I would have liked to do here is declare a generic auditor type/interface, as one would in Java for example, and have the AuditLog and ConsistencyChecks extend that class and implement something like an abstract AuditDirectory method. I think what we have now comes closest to this. Maybe the solution would be to rename AudState to Auditor and rename Auditor to something like AbstractAuditor? Please feel free to suggest an alternative approach if there's a more Go-like way of expressing what I had in mind.

Copy link
Member Author

Choose a reason for hiding this comment

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

Also, thinking ahead to implementing a CoSi-compatible auditor, AFAICT, it should be able to directly use AudState (or whatever we call it) and implement AuditDirectory() like we've done so far.

Copy link
Member

Choose a reason for hiding this comment

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

I agree, though I have no idea what it should be :(. Thus, I suggest we add a TODO here or open an issue so we can address it later.

Copy link
Member Author

@masomel masomel Aug 11, 2017

Choose a reason for hiding this comment

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

Tbh, the way it's implemented right now was according to a suggestion you made to make AudState implement Auditor and have the other two use AudState so that other kinds of auditors could implement something different. I'm a bit confused why you're suggesting now that we should change this again ;)

I need to think about it some more, but I think that the only new type of auditor which would have to implement the Auditor interface would be a blockchain based auditor. What we have right now does express what we intended, so I don't think we need to change what we have. Maybe @arlolra and @liamsi can weigh in on this, too?

@coniks-sys coniks-sys deleted a comment from vqhuy Aug 22, 2017
@coniks-sys coniks-sys deleted a comment from vqhuy Aug 22, 2017
var _ Auditor = (*AudState)(nil)

// NewAuditor instantiates a new auditor state from a persistance storage.
func NewAuditor(signKey sign.PublicKey, verified *DirSTR) *AudState {
Copy link
Member

Choose a reason for hiding this comment

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

I would expect the return type here is Auditor

Copy link
Member

Choose a reason for hiding this comment

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

We discussed about this at #170 (comment). For now, AudState has some methods which shouldn't belong to the Auditor interface.

func (h *directoryHistory) updateLatestSTR(newLatest *DirSTR) {
h.snapshots[newLatest.Epoch] = newLatest
h.latestSTR = newLatest
// updateVerifiedSTR inserts a new range of STRs into a directory history;
Copy link
Member

Choose a reason for hiding this comment

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

range of STRs

?

Copy link
Member

Choose a reason for hiding this comment

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

done.

h.updateLatestSTR(initSTR)
return h
// Audit checks that a directory's STR history
// is linear and updates the audtor's state
Copy link
Member

Choose a reason for hiding this comment

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

auditor

Copy link
Member

Choose a reason for hiding this comment

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

done.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks @c633 for taking care of this!

@masomel
Copy link
Member Author

masomel commented Aug 31, 2017

Am I right to assume that this is ready to be merged? No new comments in over a week.

@masomel masomel merged commit 9332452 into master Sep 1, 2017
@vqhuy vqhuy deleted the generic-auditor branch September 3, 2017 20:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants