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

Roster change preparation #40

Merged
merged 11 commits into from
May 1, 2020
Merged

Roster change preparation #40

merged 11 commits into from
May 1, 2020

Conversation

Gilthoniel
Copy link
Contributor

@Gilthoniel Gilthoniel commented Apr 24, 2020

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

@Gilthoniel Gilthoniel self-assigned this Apr 24, 2020
@Gilthoniel Gilthoniel added the R4M 🚀 The PR is ready to be reviewed and merged label Apr 28, 2020
@Gilthoniel Gilthoniel requested a review from nkcr April 28, 2020 09:03
Copy link
Contributor

@nkcr nkcr left a 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.

Comment on lines 40 to 43
index := i.iterator.GetNext()
if index >= 0 {
return i.roster.addrs[index]
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
index := i.iterator.GetNext()
if index >= 0 {
return i.roster.addrs[index]
}
if i.iterator.HasNext() {
return i.roster.addrs[i.iterator.GetNext()]
}

Comment on lines 56 to 59
index := i.iterator.GetNext()
if index >= 0 {
return i.roster.pubkeys[index]
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
index := i.iterator.GetNext()
if index >= 0 {
return i.roster.pubkeys[index]
}
if i.iterator.HasNext() {
return i.roster.pubkeys[i.iterator.GetNext()]
}

Comment on lines 23 to 29
func (i *iterator) GetNext() int {
if i.HasNext() {
i.index++
return i.index
}
return -1
}
Copy link
Contributor

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.

Suggested change
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
}

}

func (i *iterator) HasNext() bool {
return i.index+1 < i.roster.Len()
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 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.

// 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}}
Copy link
Contributor

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

Suggested change
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.
Copy link
Contributor

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)))
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 comment why this magic number

Comment on lines 254 to 258
var err error
fl.changeset, err = f.decodeChangeSet(src.GetChangeSet())
if err != nil {
return fl, xerrors.Errorf("couldn't decode changeset: %v", err)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
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,
}

Comment on lines 289 to 300
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
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
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
Copy link
Contributor

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

commented ;)

@Gilthoniel Gilthoniel requested a review from nkcr April 30, 2020 12:28
Copy link
Contributor

@nkcr nkcr left a 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.

@@ -60,6 +64,10 @@ func (fl forwardLink) Pack(enc encoding.ProtoMarshaler) (proto.Message, error) {
}

var err error
pb.ChangeSet, err = fl.packChangeSet(enc)
Copy link
Contributor

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
}

Copy link
Contributor Author

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,
Copy link
Contributor

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
}

Copy link
Contributor Author

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.

Comment on lines 32 to 33
- **governance** - Governance is a black box that provides to act on the
participants of a consensus.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
- **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()
Copy link
Contributor

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.

Copy link
Contributor Author

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) {
Copy link
Contributor

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 {
Copy link
Contributor

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
}

@Gilthoniel Gilthoniel requested a review from nkcr May 1, 2020 11:49
@nkcr nkcr merged commit 6509bf5 into master May 1, 2020
@Gilthoniel Gilthoniel deleted the roster_change branch May 1, 2020 12:02
bbjubjub2494 pushed a commit to bbjubjub2494/dela that referenced this pull request Aug 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
R4M 🚀 The PR is ready to be reviewed and merged
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants