-
Notifications
You must be signed in to change notification settings - Fork 344
Release 0.16 - alignment with consolidated tooling wrt chain making #501
Release 0.16 - alignment with consolidated tooling wrt chain making #501
Conversation
…nto AccountPermission
…unt and GenesisValidator
b8c93cb
to
4c1951d
Compare
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.
Looks good in terms of structure which is definitely an improvement.
I take issue with the over-defensive use of cloning everything. Often you are cloning values that are copied on the call stack anyway. Where you are dealing with pointers it ought really be part of the contract that we are not handed mutable bytes by the implementer. In terms of the actual implementations we can see that we are not passed mutable bytes and we know we are not mutating them. So I'm not sure the extra complexity is justified. Plus it signals that we need to be cloning we I am not convinced we do. Though perhaps I am missing something.
|
||
// TODO: assert valid accounts and validators | ||
// TODO: [ben] expose setting global permissions | ||
globalPermissions := ptypes.DefaultAccountPermissions.Clone() |
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 think this is necessary DefaultAccountPermissions
is a struct value so it's copied on assignment.
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.
Yes, but is a struct AccountPermissions
of a struct BasePermissions
and a slice of strings
; I believe - but not sure - that the struct BasePermissions
is treated as a pointer essentially; but definitely the Roles []string
is an effective pointer;
secondly, genesis is currently constructed with Params
as a pointer to a GenesisParams
which is a pointer to an AccountPermissions
; I dont particularly like this construction; but I didnt want to end up with a GenesisDoc
that didnt own its own data;
Arguably this does read very defensive
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.
The inner struct is just another value, the memory is copied in a single pass. See: https://play.golang.org/p/Ut_7gZ3TyJ
Yeah the slice does give you mutable access. But this is go, I think we need to choose our battles. I'd rather we were passing immutable sequences of values but we're not. And in the event we are not writing back to the roles, and that would be a weird thing to do.
@@ -28,6 +28,25 @@ func GenerateKnown(chainID, accountsPathCSV, validatorsPathCSV string) (string, | |||
} | |||
|
|||
//------------------------------------------------------------------------------------ | |||
// interface functions that are consumed by monax tooling | |||
|
|||
func GenerateGenesisFileBytes(chainName string, genesisAccounts []*GenesisAccount, |
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.
Similar to other comment, if it's convenient to pass genesisAccounts []GenesisAccount
then we could probably get away without a clone... (though we do have pointers from GenesisAccount
to AccountPermissions
, but I don't think we accidentally mutate here)
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.
in tooling there is a usage of passing slices of pointers; which is justified there because they are passed around a lot during construction;
this is why i deliberately gave tooling an interface that respects the [ ]*T
; but GenesisDoc
is constructed with [ ]T
and once GenesisDoc
is constructed changing the original argument T
should not affect the GenesisDoc
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.
thought that might be the case. Makes sense.
genesis/maker.go
Outdated
switch keyType { | ||
case "ed25519": | ||
// TODO: [ben] functionality and checks need to be inherit in the type | ||
if len(publicKeyBytes) != 32 { |
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 rather replace all magic number references with named constants
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.
yes, but tendermint/go-crypto/pub_key.go
does not have this definition; and while I agree with you. I prefer to hold off making that definition until (very soon) we make eris-db/crypto
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.
We should just name it in the same file, let's not make the perfect an enemy of the good.
genesis/maker.go
Outdated
len(publicKeyBytes)) | ||
} | ||
// ed25519 has type byte 0x01 | ||
typedPublicKeyBytes = make([]byte, 33) |
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.
likewise would prefer publicKeyLength + 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.
yes, on the same page, but without a const
, 32+1
is a bit weird
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.
yep, which is why you should introduce the constant. In the same file if necessary.
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.
Im ok with introducing the constants and moving them later
genesis/maker.go
Outdated
// prepend type byte to public key | ||
typedPublicKeyBytes = append([]byte{crypto.PubKeyTypeEd25519}, publicKeyBytes...) | ||
case "secp256k1": | ||
if len(publicKeyBytes) != 64 { |
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.
again
genesis/maker.go
Outdated
len(publicKeyBytes)) | ||
} | ||
// secp256k1 has type byte 0x02 | ||
typedPublicKeyBytes = make([]byte, 65) |
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.
same
genesis/types.go
Outdated
} | ||
// clone the public key by writing and reading over go-wire serialisation | ||
// TODO! write unit test to see whether this is correct | ||
publicKeyClone, err := crypto.PubKeyFromBytes(genesisValidator.PubKey.Bytes()) |
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 can see how this is sort of defensive. But I wonder if it is a step too far. Ultimately we have to trust that we are not being handed internal bytes slice that we might mutate. We can see for sure that we are not being handed a reference to internal bytes as it 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.
Having a Clone
in general is very good practice, because it allows you to make it explicit when you're copying data; and as a result avoid copying it when you don't have to.
Here again Clone is introduced, because on construction of the genesisDoc I want to have unique ownership of GenesisDoc
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 do get it, it's just using non-pointer values is idiomatic way of doing this in go. If this is really such a special case that we need to be extra explicit about copying then maybe. But my concern is that fighting the language like this leads to a mess/a burden we cannot hope to (would not want to) live up to everywhere.
I particularly don't like this given that we are running it through go-wire for little reason.
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.
Im not sure whether it is fighting the language or fighting bad habits
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.
using go-wire was here rather elegant; otherwise it requires many lines of reflecting which keytype it is then copying it in the correct fixed size byte array and then casting it back to the interface;
in my opinion interface PubKey
should have a Clone()
but it does not; so using the available interfaces worked quite nicely
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.
because it allows you to make it explicit when you're copying data; and as a result avoid copying it when you don't have to.
You are copying data exactly when you don't have to because PubKey.Bytes()
does a copy itself (as it ought to)
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.
but it returns a []byte as type byte prepended public key bytes; I need to then copy that byte slice in a [32]byte
or [64]byte
and then cast that to the interface; this one line captures all that;
Im fine for it to be improved in eris-db/crypto
; but right now I need a way to take deep ownership of the data in genesisDoc so that once the GenesisDoc
is created it is independent of the memory that went into creating 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.
My point is you have a PubKey, you don't need a clone, it's the same PubKey genesisValidator.PubKey
and the PubKey
interface is immutable.
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.
And you already own the memory because you created it: https://github.com/benjaminbollen/eris-db/blob/441c1a6db5b3d679b94df5bd0335ee32f5d9697e/genesis/maker.go#L77
continued in #506 |
…se-0.16-cutout-genesis Release 0.16 - alignment with consolidated tooling wrt chain making
After consolidation of eris-cm and eris-pm into eris tooling; some technical debt had to be resolved. This PR is necessary for this re-alignment in eris https://github.com/eris-ltd/eris/pull/1235 to complete.
checklist:
permissions
; merged in Cleanup: introduce word256 and remove dependency on tendermint/go-common #499genesis.GenerateGenesisFileBytes(chainName, []*GenesisAccount, []*GenesisValidator)
for tooling