Skip to content
This repository has been archived by the owner on May 13, 2022. It is now read-only.

Release 0.16 - alignment with consolidated tooling wrt chain making #501

15 changes: 15 additions & 0 deletions genesis/gen_test.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
// Copyright 2015-2017 Monax Industries Limited.
// This file is part of the Monax platform (Monax)

// Monax is free software: you can use, redistribute it and/or modify
// it only under the terms of the GNU General Public License, version
// 3, as published by the Free Software Foundation.

// Monax is distributed WITHOUT ANY WARRANTY pursuant to
// the terms of the Gnu General Public Licence, version 3, including
// (but not limited to) Clause 15 thereof. See the text of the
// GNU General Public License, version 3 for full terms.

// You should have received a copy of the GNU General Public License,
// version 3, with Monax. If not, see <http://www.gnu.org/licenses/>.

package genesis

import (
Expand Down
85 changes: 85 additions & 0 deletions genesis/genesis.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Copyright 2015-2017 Monax Industries Limited.
// This file is part of the Monax platform (Monax)

// Monax is free software: you can use, redistribute it and/or modify
// it only under the terms of the GNU General Public License, version
// 3, as published by the Free Software Foundation.

// Monax is distributed WITHOUT ANY WARRANTY pursuant to
// the terms of the Gnu General Public Licence, version 3, including
// (but not limited to) Clause 15 thereof. See the text of the
// GNU General Public License, version 3 for full terms.

// You should have received a copy of the GNU General Public License,
// version 3, with Monax. If not, see <http://www.gnu.org/licenses/>.

package genesis

import (
"bytes"
"encoding/json"
"time"

ptypes "github.com/eris-ltd/eris-db/permission/types"
wire "github.com/tendermint/go-wire"
)

// MakeGenesisDocFromAccounts takes a chainName and a slice of pointers to GenesisAccount,
// and a slice of pointers to GenesisValidator to construct a GenesisDoc, or returns an error on
// failure. In particular MakeGenesisDocFromAccount uses the local time as a
// timestamp for the GenesisDoc.
func MakeGenesisDocFromAccounts(chainName string, accounts []*GenesisAccount,
validators []*GenesisValidator) (GenesisDoc, error) {

// TODO: assert valid accounts and validators
// TODO: [ben] expose setting global permissions
globalPermissions := ptypes.DefaultAccountPermissions.Clone()
Copy link
Contributor

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.

Copy link
Contributor Author

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

Copy link
Contributor

@silasdavis silasdavis Feb 21, 2017

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.

genesisParameters := &GenesisParams{
GlobalPermissions: &globalPermissions,
}
// copy slice of pointers to accounts into slice of accounts
accountsCopy := make([]GenesisAccount, len(accounts))
for i, genesisAccount := range accounts {
accountsCopy[i] = genesisAccount.Clone()
}
// copy slice of pointers to validators into slice of validators
validatorsCopy := make([]GenesisValidator, len(validators))
for i, genesisValidator := range validators {
genesisValidatorCopy, err := genesisValidator.Clone()
if err != nil {
return GenesisDoc{}, err
}
validatorsCopy[i] = genesisValidatorCopy
}
genesisDoc := GenesisDoc{
GenesisTime: time.Now(),
// TODO: this needs to be corrected for ChainName, and ChainId
// is the derived hash from the GenesisDoc serialised bytes
ChainID: chainName,
Params: genesisParameters,
Accounts: accountsCopy,
Validators: validatorsCopy,
}
return genesisDoc, nil
}

// GetGenesisFileBytes returns the JSON (not-yet) canonical bytes for a given
// GenesisDoc or an error. In a first rewrite, rely on go-wire
// for the JSON serialisation with type-bytes.
func GetGenesisFileBytes(genesisDoc *GenesisDoc) ([]byte, error) {

// TODO: write JSON in canonical order
var err error
buffer, n := new(bytes.Buffer), new(int)
// write JSON with go-wire type-bytes (for public keys)
wire.WriteJSON(genesisDoc, buffer, n, &err)
if err != nil {
return nil, err
}
// rewrite buffer with indentation
indentedBuffer := new(bytes.Buffer)
if err := json.Indent(indentedBuffer, buffer.Bytes(), "", "\t"); err != nil {
return nil, err
}
return indentedBuffer.Bytes(), nil
}
19 changes: 19 additions & 0 deletions genesis/make_genesis_file.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,25 @@ func GenerateKnown(chainID, accountsPathCSV, validatorsPathCSV string) (string,
time.Now())
}

//------------------------------------------------------------------------------------
// interface functions that are consumed by monax tooling

func GenerateGenesisFileBytes(chainName string, genesisAccounts []*GenesisAccount,
Copy link
Contributor

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)

Copy link
Contributor Author

@benjaminbollen benjaminbollen Feb 21, 2017

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

Copy link
Contributor

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.

genesisValidators []*GenesisValidator) ([]byte, error) {
genesisDoc, err := MakeGenesisDocFromAccounts(chainName, genesisAccounts, genesisValidators)

buf, buf2, n := new(bytes.Buffer), new(bytes.Buffer), new(int)
wire.WriteJSON(genesisDoc, buf, n, &err)
if err != nil {
return nil, err
}
if err := json.Indent(buf2, buf.Bytes(), "", "\t"); err != nil {
return nil, err
}

return buf2.Bytes(), nil
}

//------------------------------------------------------------------------------------
// core functions that provide functionality for monax tooling in v0.16

Expand Down
85 changes: 85 additions & 0 deletions genesis/maker.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Copyright 2015-2017 Monax Industries Limited.
// This file is part of the Monax platform (Monax)

// Monax is free software: you can use, redistribute it and/or modify
// it only under the terms of the GNU General Public License, version
// 3, as published by the Free Software Foundation.

// Monax is distributed WITHOUT ANY WARRANTY pursuant to
// the terms of the Gnu General Public Licence, version 3, including
// (but not limited to) Clause 15 thereof. See the text of the
// GNU General Public License, version 3 for full terms.

// You should have received a copy of the GNU General Public License,
// version 3, with Monax. If not, see <http://www.gnu.org/licenses/>.

package genesis

import (
"fmt"

ptypes "github.com/eris-ltd/eris-db/permission/types"

"github.com/tendermint/go-crypto"
)

const (
PublicKeyEd25519ByteLength int = 32
PublicKeySecp256k1ByteLength int = 64
)

// NewGenesisAccount returns a new GenesisAccount
func NewGenesisAccount(address []byte, amount int64, name string,
permissions *ptypes.AccountPermissions) *GenesisAccount {
return &GenesisAccount{
Address: address,
Amount: amount,
Name: name,
Permissions: permissions,
}
}

func NewGenesisValidator(amount int64, name string, unbondToAddress []byte,
unbondAmount int64, keyType string, publicKeyBytes []byte) (*GenesisValidator, error) {
// convert the key bytes into a typed fixed size byte array
var typedPublicKeyBytes []byte
switch keyType {
case "ed25519":
// TODO: [ben] functionality and checks need to be inherit in the type
if len(publicKeyBytes) != PublicKeyEd25519ByteLength {
return nil, fmt.Errorf("Invalid length provided for ed25519 public key (len %v)",
len(publicKeyBytes))
}
// ed25519 has type byte 0x01
typedPublicKeyBytes = make([]byte, PublicKeyEd25519ByteLength+1)
// prepend type byte to public key
typedPublicKeyBytes = append([]byte{crypto.PubKeyTypeEd25519}, publicKeyBytes...)
case "secp256k1":
if len(publicKeyBytes) != PublicKeySecp256k1ByteLength {
return nil, fmt.Errorf("Invalid length provided for secp256k1 public key (len %v)",
len(publicKeyBytes))
}
// secp256k1 has type byte 0x02
typedPublicKeyBytes = make([]byte, PublicKeySecp256k1ByteLength+1)
// prepend type byte to public key
typedPublicKeyBytes = append([]byte{crypto.PubKeyTypeSecp256k1}, publicKeyBytes...)
default:
return nil, fmt.Errorf("Unsupported key type (%s)", keyType)
}
newPublicKey, err := crypto.PubKeyFromBytes(typedPublicKeyBytes)
if err != nil {
return nil, err
}
// ability to unbond to multiple accounts currently unused
var unbondTo []BasicAccount

return &GenesisValidator{
PubKey: newPublicKey,
Amount: unbondAmount,
Name: name,
UnbondTo: append(unbondTo, BasicAccount{
Address: unbondToAddress,
Amount: unbondAmount,
}),
}, nil
}
91 changes: 91 additions & 0 deletions genesis/types.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
// Copyright 2015-2017 Monax Industries Limited.
// This file is part of the Monax platform (Monax)

// Monax is free software: you can use, redistribute it and/or modify
// it only under the terms of the GNU General Public License, version
// 3, as published by the Free Software Foundation.

// Monax is distributed WITHOUT ANY WARRANTY pursuant to
// the terms of the Gnu General Public Licence, version 3, including
// (but not limited to) Clause 15 thereof. See the text of the
// GNU General Public License, version 3 for full terms.

// You should have received a copy of the GNU General Public License,
// version 3, with Monax. If not, see <http://www.gnu.org/licenses/>.

package genesis

import (
Expand All @@ -6,6 +21,7 @@ import (
"time"

ptypes "github.com/eris-ltd/eris-db/permission/types"

"github.com/tendermint/go-crypto"
"github.com/tendermint/go-wire"
)
Expand Down Expand Up @@ -37,6 +53,19 @@ type GenesisValidator struct {
UnbondTo []BasicAccount `json:"unbond_to"`
}

// GenesisPrivateValidator marshals the state of the private
// validator for the purpose of Genesis creation; and hence
// is defined in genesis and not under consensus, where
// PrivateValidator (currently inherited from Tendermint) is.
type GenesisPrivateValidator struct {
Address string `json:"address"`
PubKey []interface{} `json:"pub_key"`
PrivKey []interface{} `json:"priv_key"`
LastHeight int64 `json:"last_height"`
LastRound int64 `json:"last_round"`
LastStep int64 `json:"last_step"`
}

type GenesisParams struct {
GlobalPermissions *ptypes.AccountPermissions `json:"global_permissions"`
}
Expand Down Expand Up @@ -65,3 +94,65 @@ func GenesisDocFromJSON(jsonBlob []byte) (genState *GenesisDoc) {
}
return
}

//------------------------------------------------------------
// Methods for genesis types
// NOTE: breaks formatting convention
// TODO: split each genesis type in its own file definition

//------------------------------------------------------------
// GenesisAccount methods

// Clone clones the genesis account
func (genesisAccount *GenesisAccount) Clone() GenesisAccount {
// clone the address
addressClone := make([]byte, len(genesisAccount.Address))
copy(addressClone, genesisAccount.Address)
// clone the account permissions
accountPermissionsClone := genesisAccount.Permissions.Clone()
return GenesisAccount{
Address: addressClone,
Amount: genesisAccount.Amount,
Name: genesisAccount.Name,
Permissions: &accountPermissionsClone,
}
}

//------------------------------------------------------------
// GenesisValidator methods

// Clone clones the genesis validator
func (genesisValidator *GenesisValidator) Clone() (GenesisValidator, error) {
if genesisValidator == nil {
return GenesisValidator{}, fmt.Errorf("Cannot clone nil GenesisValidator.")
}
if genesisValidator.PubKey == nil {
return GenesisValidator{}, fmt.Errorf("Invalid GenesisValidator %s with nil public key.",
genesisValidator.Name)
}
// clone the addresses to unbond to
unbondToClone := make([]BasicAccount, len(genesisValidator.UnbondTo))
for i, basicAccount := range genesisValidator.UnbondTo {
unbondToClone[i] = basicAccount.Clone()
}
return GenesisValidator{
PubKey: genesisValidator.PubKey,
Amount: genesisValidator.Amount,
Name: genesisValidator.Name,
UnbondTo: unbondToClone,
}, nil
}

//------------------------------------------------------------
// BasicAccount methods

// Clone clones the basic account
func (basicAccount *BasicAccount) Clone() BasicAccount {
// clone the address
addressClone := make([]byte, len(basicAccount.Address))
copy(addressClone, basicAccount.Address)
return BasicAccount{
Address: addressClone,
Amount: basicAccount.Amount,
}
}
2 changes: 1 addition & 1 deletion manager/eris-mint/state/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ var g1 = fmt.Sprintf(`
{
"address": "%X",
"amount": %d,
"name": "%s",
"name": "%s",
"permissions": {
"base": {
"perms": %d,
Expand Down
Loading