-
Notifications
You must be signed in to change notification settings - Fork 14
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
Roster change preparation #40
Conversation
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.
Nice work! As usual, here is my "general-but-not-thorough" review.
ledger/byzcoin/roster.go
Outdated
index := i.iterator.GetNext() | ||
if index >= 0 { | ||
return i.roster.addrs[index] | ||
} |
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.
index := i.iterator.GetNext() | |
if index >= 0 { | |
return i.roster.addrs[index] | |
} | |
if i.iterator.HasNext() { | |
return i.roster.addrs[i.iterator.GetNext()] | |
} |
ledger/byzcoin/roster.go
Outdated
index := i.iterator.GetNext() | ||
if index >= 0 { | ||
return i.roster.pubkeys[index] | ||
} |
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.
index := i.iterator.GetNext() | |
if index >= 0 { | |
return i.roster.pubkeys[index] | |
} | |
if i.iterator.HasNext() { | |
return i.roster.pubkeys[i.iterator.GetNext()] | |
} |
ledger/byzcoin/roster.go
Outdated
func (i *iterator) GetNext() int { | ||
if i.HasNext() { | ||
i.index++ | ||
return i.index | ||
} | ||
return -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.
It should be the user's responsibility to call HasNext()
before a GetNext()
, therefore I wouldn't add a special case there, as the responsibility is commonly defined for an iterator: if HasNext()
returns true, then GetNext()
returns something, else there can't be any assumption.
func (i *iterator) GetNext() int { | |
if i.HasNext() { | |
i.index++ | |
return i.index | |
} | |
return -1 | |
} | |
func (i *iterator) GetNext() int { | |
res := i.index // for an index that starts at 0 | |
i.index++ | |
return res | |
} |
ledger/byzcoin/roster.go
Outdated
} | ||
|
||
func (i *iterator) HasNext() bool { | ||
return i.index+1 < i.roster.Len() |
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 find it more natural to start the index at 0, it also has the advantage of using the default/zero value in a meaningful way when creating the iterator.
ledger/byzcoin/roster.go
Outdated
// AddressIterator implements mino.Players. It returns an iterator of the | ||
// addresses of the roster in a deterministic order. | ||
func (r roster) AddressIterator() mino.AddressIterator { | ||
return &addressIterator{iterator: &iterator{roster: &r, index: -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.
based on my previous comment
return &addressIterator{iterator: &iterator{roster: &r, index: -1}} | |
return &addressIterator{iterator: &iterator{roster: &r}} |
enc encoding.ProtoMarshaler) ([]*Player, error) { | ||
|
||
if len(in) == 0 { | ||
// Save some bytes in the message with a nil array. |
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.
a penny saved is a penny earned 😄
} | ||
} | ||
|
||
buffer := make([]byte, 4+(4*len(fl.changeset.Remove))) |
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 comment why this magic number
consensus/cosipbft/forward_link.go
Outdated
var err error | ||
fl.changeset, err = f.decodeChangeSet(src.GetChangeSet()) | ||
if err != nil { | ||
return fl, xerrors.Errorf("couldn't decode changeset: %v", err) | ||
} |
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.
var err error | |
fl.changeset, err = f.decodeChangeSet(src.GetChangeSet()) | |
if err != nil { | |
return fl, xerrors.Errorf("couldn't decode changeset: %v", err) | |
} | |
changeset, err := f.decodeChangeSet(src.GetChangeSet()) | |
if err != nil { | |
return fl, xerrors.Errorf("couldn't decode changeset: %v", err) | |
} | |
fl = forwardLink{ | |
from: src.GetFrom(), | |
to: src.GetTo(), | |
changeset: changeset, | |
} |
consensus/cosipbft/forward_link.go
Outdated
changeset := viewchange.ChangeSet{ | ||
Leader: in.GetLeader(), | ||
Remove: in.GetRemove(), | ||
} | ||
|
||
var err error | ||
changeset.Add, err = f.decodeAdd(in.GetAdd()) | ||
if err != nil { | ||
return changeset, xerrors.Errorf("couldn't decode add: %v", err) | ||
} | ||
|
||
return changeset, nil |
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.
changeset := viewchange.ChangeSet{ | |
Leader: in.GetLeader(), | |
Remove: in.GetRemove(), | |
} | |
var err error | |
changeset.Add, err = f.decodeAdd(in.GetAdd()) | |
if err != nil { | |
return changeset, xerrors.Errorf("couldn't decode add: %v", err) | |
} | |
return changeset, nil | |
add, err := f.decodeAdd(in.GetAdd()) | |
if err != nil { | |
return changeset, xerrors.Errorf("couldn't decode add: %v", err) | |
} | |
changeset := viewchange.ChangeSet{ | |
Leader: in.GetLeader(), | |
Remove: in.GetRemove(), | |
Add: add, | |
} | |
return changeset, nil |
func (f *chainFactory) FromProto(pb proto.Message) (consensus.Chain, error) { | ||
chain, err := f.unsecureChainFactory.FromProto(pb) | ||
if err != nil { | ||
return nil, err |
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.
a forgotten error wrap? Otherwise I would comment why.
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.
commented ;)
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 wasn't sure you would welcome my weird comment about "get and process" lines, so I took the opportunity now to point out some other sections that I previously left. If you agree I'll update the guidelines to include this case.
consensus/cosipbft/forward_link.go
Outdated
@@ -60,6 +64,10 @@ func (fl forwardLink) Pack(enc encoding.ProtoMarshaler) (proto.Message, error) { | |||
} | |||
|
|||
var err error | |||
pb.ChangeSet, err = fl.packChangeSet(enc) |
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.
As a general guideline I would recommend that we first gather the needed variables and then define the structure. What do you think?
// Pack returns the protobuf message of the forward link.
func (fl forwardLink) Pack(enc encoding.ProtoMarshaler) (proto.Message, error) {
changeSet, err := fl.packChangeSet(enc)
if err != nil {
return nil, xerrors.Errorf("couldn't pack changeset: %v", err)
}
var prepare *any.Any
if fl.prepare != nil {
prepare, err = enc.PackAny(fl.prepare)
if err != nil {
return nil, xerrors.Errorf("couldn't pack prepare signature: %v", err)
}
}
var commit *any.Any
if fl.commit != nil {
commit, err = enc.PackAny(fl.commit)
if err != nil {
return nil, xerrors.Errorf("couldn't pack commit signature: %v", err)
}
}
pb := &ForwardLinkProto{
From: fl.from,
To: fl.to,
ChangeSet: changeSet,
Prepare: prepare,
Commit: commit,
}
return pb, nil
}
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.
General guideline, but like below it sometimes makes sense not to.
@@ -159,6 +186,27 @@ func (a pbftActor) Propose(p consensus.Proposal, players mino.Players) error { | |||
return nil | |||
} | |||
|
|||
func (a pbftActor) newPrepareRequest(prop consensus.Proposal, |
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.
func (a pbftActor) newPrepareRequest(prop consensus.Proposal,
cs viewchange.ChangeSet) (Prepare, error) {
forwardLink := forwardLink{
from: prop.GetPreviousHash(),
to: prop.GetHash(),
changeset: cs,
}
digest, err := forwardLink.computeHash(a.hashFactory.New(), a.encoder)
if err != nil {
return nil, xerrors.Errorf("couldn't compute hash: %v", err)
}
req := Prepare{
proposal: prop,
digest: digest,
}
return req, nil
}
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 an example why it really depends on the situation because there I return a struct so the nil does not work. Sometimes it's nice to declare the object at the beginning and fill it step by step so you can return the said object if an error occurred.
docs/introduction.md
Outdated
- **governance** - Governance is a black box that provides to act on the | ||
participants of a consensus. |
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.
- **governance** - Governance is a black box that provides to act on the | |
participants of a consensus. | |
- **governance** - Governance is a black box that gives the ability to act on | |
the participants of a consensus. |
return xerrors.Errorf("couldn't store genesis payload: %v", err) | ||
} | ||
|
||
payload.Footprint = page.GetFootprint() |
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 find this section strange: You need a payload to create a page to create a footprint for that same payload. I don't have the whole picture in mind so that may make perfect sense, just noticing it.
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.
Basically you apply the transactions of the payload to the inventory to get the footprint back.
|
||
// Pack implements encoding.Packable. It returns the protobuf message for the | ||
// roster. | ||
func (r roster) Pack(enc encoding.ProtoMarshaler) (proto.Message, 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.
func (r roster) Pack(enc encoding.ProtoMarshaler) (proto.Message, error) {
addrs := make([][]byte, r.Len())
pubKeys := make([]*any.Any, r.Len())
var err error
for i, addr := range r.addrs {
addrs[i], err = addr.MarshalText()
if err != nil {
return nil, xerrors.Errorf("couldn't marshal address: %v", err)
}
pubKeys[i], err = enc.PackAny(r.pubkeys[i])
if err != nil {
return nil, xerrors.Errorf("couldn't pack public key: %v", err)
}
}
pb := &Roster{
Addresses: addrs,
PublicKeys: pubKey,
}
return pb, nil
}
} | ||
} | ||
|
||
func (f rosterFactory) New(authority crypto.CollectiveAuthority) roster { |
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.
func (f rosterFactory) New(authority crypto.CollectiveAuthority) roster {
addrs := make([]mino.Address, authority.Len())
pubKeys := make([]crypto.PublicKey, authority.Len())
addrIter := authority.AddressIterator()
pubkeyIter := authority.PublicKeyIterator()
for i := 0; addrIter.HasNext() && pubkeyIter.HasNext(); i++ {
addrs[i] = addrIter.GetNext()
pubkeys[i] = pubkeyIter.GetNext()
}
roster := roster{
addrs: addrs,
pubkeys: pubKeys,
}
return roster
}
Roster change preparation
This refactors the roster abstraction to move it from the blockchain module to the consensus one as some could not actually depend on a roster (PoW). It's up to the consensus to control it, like cosipbft must verify the leader is proposing.
Also: some refactoring in Byzcoin
Note: Missing roster txs that will come later alongside Byzcoin unit tests