[Core] Externalize a shared Mempool interface & implementation - (Issue #388)#437
[Core] Externalize a shared Mempool interface & implementation - (Issue #388)#437
Conversation
|
Hey @Olshansk I would really appreciate a quick glance at this one, ONLY TWO FILES! Au contraire, if this sucks just delete the branch and let me know :) 🙏 |
Olshansk
left a comment
There was a problem hiding this comment.
Fascinating. I like the direction and also see us just open-sourcing this as a standalone
package.
Please proceed!
|
The next batch, that will include the below todos, should be the last one and then I guess this is ready for a full-fledged review. TODO:
I have added tests for the simplest implementation to give you an idea of what I am doing. |
Signed-off-by: Alessandro De Blasis <[email protected]>
|
Looking for a couple of smarter eyes on this, E2E tests in consensus are failing at the moment, I am sure it's something stupid but I have tunnel vision now |
|
As discussed on discord, I identified and addressed the issue in c0f7a39 From discord:
@Olshansk , @gokutheengineer and myself concurred that there's some room for improvement wrt determinism, a followup issue/PR will make life and DevEx easier going forward 🚀 |
|
Yo @Olshansk! I think this is ready for another pass. PTAL 🙏 |
consensus/hotstuff_leader.go
Outdated
| // Likely to be `nil` if blockchain is progressing well. | ||
| // TECHDEBT: How do we properly validate `prepareQC` here? | ||
| highPrepareQC := m.findHighQC(m.consensusMessagePool[NewRound].GetAll()) //TODO: improve this | ||
| // DISCUSS: could this be improved by incrementally keeping track of highQC when we add/remove messages to the mempool? Probably premature optimization for now but something to keep in mind. |
There was a problem hiding this comment.
| // DISCUSS: could this be improved by incrementally keeping track of highQC when we add/remove messages to the mempool? Probably premature optimization for now but something to keep in mind. | |
| // CONSIDERATION(M5): could this be improved by incrementally keeping track of highQC when we add/remove messages to the mempool? Probably premature optimization for now but something to keep in mind. |
| } | ||
|
|
||
| func (mp *hotstuffFifoMempool) Clear() { | ||
| mp.g.Clear() |
There was a problem hiding this comment.
Kind of.
To me it just seems to make more sense to lock on the outer structure before operating on the inner structure.
Might not make a difference though.
| }, | ||
| }, | ||
| } | ||
| for _, tt := range tests { |
There was a problem hiding this comment.
This test suite is REALLY good
Olshansk
left a comment
There was a problem hiding this comment.
One last round of small comments and we should be able to merge it in tomorrow
|
|
||
| // Clear clears the mempool | ||
| func (t *txFIFOMempool) Clear() { | ||
| t.g.Clear() |
There was a problem hiding this comment.
Same as before. My inutition just makes me think:
- Lock outer structure
- Clear inner structure
2.1. Capture inner lock
2.2. Unlock inner lock - Clear outer strcture
- Unlock outer structure
There was a problem hiding this comment.
My 🚂 of 🤔 is:
- Do what the generic implementation does,
- Do what's special to this implementation
Basically this: b875b37
There was a problem hiding this comment.
Won't push back against this since it doesn't matter.
Going to share my personal 🚄 of 🤔 thought:
- In polymorphism (when a subclass inherits from a superclass), we usually do:
super.constructor()
self.constructioner()
- In this case, where the generic implementation is an internal field, I'm thinking:
self.clearFields()
attributes.clearFields()
There was a problem hiding this comment.
Well, it's not a rule, you can call the super before or after depending on how the subclass needs to behave.
If for example super.constructor() prints something that is dependent on some internal state (accessible and modifiable by the self, it makes sense for the self.constructioner() to happen before.
| type args struct { | ||
| maxTxBytes uint64 | ||
| maxTxs uint32 | ||
| initialTxs *[][]byte |
There was a problem hiding this comment.
-
Remove pointer?
1.1 Why are we doing a pointer to a slice? When slices are passed around, it's already just a reference to the first element.
1.2 If we do this, we should do it foractionstoo -
If we don't do this, why is this a pointer but
wantItemsis not?
The diagram here helped me think through it: https://medium.com/swlh/golang-tips-why-pointers-to-slices-are-useful-and-how-ignoring-them-can-lead-to-tricky-bugs-cac90f72e77b
There was a problem hiding this comment.
I see the use case and raise you this mini demo:
If we just don't set a slice, it's nil by default.
I would request one of following:
- Document (in the struct next to the field) why it it's a pointer
- Not use a pointer at all
Source code for reference:
package main
import "fmt"
func main() {
type args struct {
ptrSlice *[]byte
slice []byte
}
a := &args{
ptrSlice: &[]byte{},
slice: []byte{},
}
b := &args{}
fmt.Println("a.ptrSlice:", a.ptrSlice == nil)
fmt.Println("a.slice :", a.slice == nil)
fmt.Println("b.ptrSlice:", b.ptrSlice == nil)
fmt.Println("b.slice :", b.slice == nil)
}…ze-mempool Signed-off-by: Alessandro De Blasis <[email protected]>
|
@Olshansk I think this is almost there a couple of open points that might have a quick turnaround anyway but yeah, I like this. |
|
@deblasis Just followed up on one comment and nothing else: #437 (comment) |





Description
This PR Makes the
Mempoolinterface and implementation a common high-level type that can be reused across different modulesIssue
Fixes #388
Type of change
Please mark the relevant option(s):
List of changes
Testing
make develop_testREADMERequired Checklist
If Applicable Checklist
shared/docs/*if I updatedshared/*README(s)