Skip to content

all, state: unexpose GenesisDoc, ChainID fields make them accessor methods#676

Merged
ebuchman merged 6 commits intodevelopfrom
state-unexpose-genesisDoc-chainID
Oct 19, 2017
Merged

all, state: unexpose GenesisDoc, ChainID fields make them accessor methods#676
ebuchman merged 6 commits intodevelopfrom
state-unexpose-genesisDoc-chainID

Conversation

@odeke-em
Copy link
Contributor

Fixes #671

Unexpose GenesisDoc and ChainID fields to avoid them being
serialized to the DB on every block write/state.Save()

A GenesisDoc can now be alternatively written to the state's
database, by serializing its JSON as a value of key "genesis-doc".

There are now accessors and a setter for these attributes:

  • state.GenesisDoc() (*types.GenesisDoc, error)
  • state.ChainID() (string, error)
  • state.SetGenesisDoc(*types.GenesisDoc)

This is a breaking change since it changes how the state's
serialization and requires that if loading the GenesisDoc entirely
from the database, you'll need to set its value in the database
as the GenesisDoc's JSON marshaled bytes.

state/state.go Outdated
// parses the GenesisDoc from that memoizing it for later use.
// If you'd like to change the value of the GenesisDoc, invoke SetGenesisDoc.
func (s *State) GenesisDoc() (*types.GenesisDoc, error) {
s.mtx.Lock()
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not really, if the genesisDoc wasn't set to begin with, we have to retrieve it from the DB.

state/state.go Outdated
}

func (s *State) ChainID() (string, error) {
genDoc, err := s.GenesisDoc()
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We need to load the genesisDoc from the DB if unset hence the need for 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.

The code you linked is in a function whose comment says that it is used in tests

tendermint/state/state.go

Lines 343 to 346 in 925696c

// MakeGenesisState creates state from types.GenesisDoc.
//
// Used in tests.
func MakeGenesisState(db dbm.DB, genDoc *types.GenesisDoc) (*State, error) {

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I initially had it like that but in the description of the feature request @ebuchman says

We can provide methods on State to fetch them instead, and we can store them under special keys in the state database

which is why I do the fetches in the DB and store them respectively. Perhaps we could discuss the feature more and get a basic spec there, to come to consensus ;)

Copy link
Contributor

@melekes melekes Sep 23, 2017

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh, I see. Forget everything I wrote then. I should be more careful about details

Copy link
Contributor

Choose a reason for hiding this comment

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

Need to remember not to do any reviews at night

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not a problem at all, they are great questions and better for simplicity, so no biggie.

state/state.go Outdated

// SetGenesisDoc sets the internal genesisDoc, but doesn't
// serialize it to the database, until Save is invoked.
func (s *State) SetGenesisDoc(genDoc *types.GenesisDoc) {
Copy link
Contributor

Choose a reason for hiding this comment

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

second attempt :) what is the purpose of this? if we know that we set genesis doc only once during startup

Copy link
Contributor Author

Choose a reason for hiding this comment

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

IMHO that's coupling too much of the functionality into startup time, and as I had mentioned
the requirements of this package warrant us loading and setting the genesisDoc from and into the DB respectively. Because we are unexposing genesisDoc, SetGenesisDoc is the setter. However, I haven't yet seen any place in our code in which we change the GenesisDoc so you have a point here.

state/state.go Outdated
ChainID: genDoc.ChainID,
db: db,

cachedGenesisDoc: genDoc,
Copy link
Contributor

Choose a reason for hiding this comment

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

can be genesisDoc

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Roger that, thanks.

state/state.go Outdated
// its database the JSON marshaled bytes keyed by "genesis-doc", and
// parses the GenesisDoc from that memoizing it for later use.
// If you'd like to change the value of the GenesisDoc, invoke SetGenesisDoc.
func (s *State) GenesisDoc() (*types.GenesisDoc, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Don't think that GenesisDoc() or ChainID() methods should return an error. If we know that genesis file is mandatory and TM will not work without it, maybe we can just throw a panic. That way we won't be needing to handle all these errors like https://github.com/tendermint/tendermint/pull/676/files#diff-80343e80650fe43a4394fc26afd5cb3bR508. I want to hear other opinions anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's a justified concern, it makes sense to simplify the PR more, which is nice. However, the requirements of the PR request that we instead have a way of alternatively loading the genesisDoc and chainID after loading them from a DB is what warrants us returning an error
since:

  1. Non-existent data
  2. Invalid data stored

Otherwise I'd have agreed that the PR can just be simplified to a single set and panic as you advise.

Copy link
Contributor

Choose a reason for hiding this comment

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

Agree, we should not return an error. This is a panic scenario.

state/state.go Outdated
defer s.mtx.Unlock()

if s.cachedGenesisDoc == nil {
retrGenesisDocBytes := s.db.Get(genesisDBKey)
Copy link
Contributor

Choose a reason for hiding this comment

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

what retr stands for? can't we just call it bytes or jsonBytes

Copy link
Contributor Author

Choose a reason for hiding this comment

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

retr --> retrieve*
Sure, I'll update that to your suggestion, thanks.

state/state.go Outdated
// should not change
GenesisDoc *types.GenesisDoc
ChainID string
// cachedGenesisDoc is the memoized genesisDoc to cut down
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this comment should go into git commit msg

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'd rather keep it though as a mention for the future and purpose. Without it I feel like we'll be asking ourselves why we didn't just expose it as GenesisDoc, and also it is already mentioned in the git commit message :)

@odeke-em odeke-em force-pushed the state-unexpose-genesisDoc-chainID branch from 53f0fcc to ef17728 Compare September 24, 2017 23:31
@ebuchman
Copy link
Contributor

ebuchman commented Oct 1, 2017

Thanks odeke. Note this will be a breaking change so not priority until we're ready for develop to be breaking. Also need to consider exactly how we want to do this - the goal with State is for it to be as simple and non-mutable as possible.

@odeke-em
Copy link
Contributor Author

odeke-em commented Oct 1, 2017

Thanks for the review @ebuchman and welcome back! So we'll actually need your input on:

  1. Do we want the ability to load the Genesis from the DB itself? @melekes had the impression that we only have to save it once, at startup time, I had the reverse impression that we need to be able to set, get, as well as load it from the DB

@ebuchman
Copy link
Contributor

ebuchman commented Oct 2, 2017

We only need to set it once, at startup time. It's not something that would ever change. Only question is whether we should load it from DB every time or if we should cache it in the state. Leaning towards loading from DB every time since it's rarely accessed and we want to keep the State struct simple as possible (ie. no private fields).

That said, we could also cache it in the rpc package where it's actually asked for

@ebuchman
Copy link
Contributor

ebuchman commented Oct 2, 2017

We actually already do set the GenesisDoc in the rpc, so we may not need it in the state at all!

We'll have to move the state.GenesisDoc.ConsensusParams so we can still access those from the state (since they might change), but we knew that was coming

@melekes
Copy link
Contributor

melekes commented Oct 5, 2017

Need this for #564. @odeke-em I can finish this PR if you don't have time

@melekes
Copy link
Contributor

melekes commented Oct 5, 2017

I am gonna work on this right now.

@melekes melekes force-pushed the state-unexpose-genesisDoc-chainID branch from ef17728 to 03d098c Compare October 5, 2017 13:06
@melekes
Copy link
Contributor

melekes commented Oct 5, 2017

@odeke-em @ebuchman take a look at 8bc0098.

@codecov-io
Copy link

codecov-io commented Oct 5, 2017

Codecov Report

Merging #676 into develop will decrease coverage by 0.58%.
The diff coverage is 70.73%.

@@             Coverage Diff             @@
##           develop     #676      +/-   ##
===========================================
- Coverage    57.85%   57.26%   -0.59%     
===========================================
  Files           82       82              
  Lines         8436     8453      +17     
===========================================
- Hits          4881     4841      -40     
- Misses        3142     3188      +46     
- Partials       413      424      +11

@melekes melekes force-pushed the state-unexpose-genesisDoc-chainID branch from 20758c8 to 8bc0098 Compare October 5, 2017 13:51
dbm "github.com/tendermint/tmlibs/db"
"github.com/tendermint/go-wire"
"github.com/tendermint/tendermint/types"
. "github.com/tendermint/tmlibs/common"
Copy link
Contributor

Choose a reason for hiding this comment

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

cmn

@odeke-em
Copy link
Contributor Author

odeke-em commented Oct 5, 2017

@melekes sorry for the late reply, I was away from all devices for a whole lot of hours, but sure, please feel free to take over it.

node/node.go Outdated
return nil, err
}

genDoc, err := genesisDocProvider()
Copy link
Contributor

Choose a reason for hiding this comment

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

this assumes the genesis will always be available, even if we've already run the node. it's probably ok, but not sure we want to make that assumption

Copy link
Contributor

Choose a reason for hiding this comment

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

@jaekwon do you want to comment on this?

Copy link
Contributor

Choose a reason for hiding this comment

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

If we start a node, and then later the genesis file is changed, we will not be able to restart the node unless we can recover that genesis file. So I think it's worth having the genesis saved in the database to prevent a certain class of user errors. What do you think?

Copy link
Contributor

@melekes melekes Oct 13, 2017

Choose a reason for hiding this comment

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

don't know. I am trying to come up with a scenario where it will be useful.

1. user loses state

then we'll need original genesis file to MakeGenesisState, but since we store all DBs together, a user will most likely lose genesis state too, so no point of storing it

2. user accidentally changes the genesis json (or some hacker changes it)

then TM will either fail to start due to a parsing error / missing genesis file error OR RPC will be serving incorrect genesis file. Is it worth saving it in the DB for the purpose of preventing such errors? I am not sure.

Copy link
Contributor

Choose a reason for hiding this comment

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

Date:   Fri Oct 13 13:11:16 2017 +0400

    save genesis doc in DB to prevent user errors

    https://github.com/tendermint/tendermint/pull/676#discussion_r144411458

─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
modified: node/node.go
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
@ node.go:5 @ package node

import (
    "bytes"
    "encoding/json"
    "errors"
    "fmt"
    "net"
@ node.go:137 @ func NewNode(config *cfg.Config,
        return nil, err
    }

    genDoc, err := genesisDocProvider()
    // Get genesis doc
    genesisDB, err := dbProvider(&DBContext{"genesis", config})
    if err != nil {
        return nil, err
    }
    genDoc, err := loadGenesisDoc(genesisDB)
    if err != nil {
        genDoc, err = genesisDocProvider()
        if err != nil {
            return nil, err
        }
        // save genesis doc to prevent a certain class of user errors (e.g. when it
        // was changed, accidentally or not)
        err = saveGenesisDoc(genesisDB, genDoc)
        if err != nil {
            return nil, err
        }
    }

    state := sm.LoadState(stateDB)
    if state == nil {
@ node.go:554 @ func (n *Node) DialSeeds(seeds []string) error {
}

//------------------------------------------------------------------------------

var (
    genesisDocKey = []byte("genesisDoc")
)

func loadGenesisDoc(db dbm.DB) (*types.GenesisDoc, error) {
    bytes := db.Get(genesisDocKey)
    if len(bytes) == 0 {
        return nil, errors.New("Genesis doc not found")
    } else {
        var genDoc *types.GenesisDoc
        err := json.Unmarshal(bytes, &genDoc)
        return genDoc, err
    }
}

func saveGenesisDoc(db dbm.DB, genDoc *types.GenesisDoc) error {
    bytes, err := json.Marshal(genDoc)
    if err != nil {
        return err
    }
    db.SetSync(genesisDocKey, bytes)
    return nil
}

I wrote the code and can push it if we agree that we need to save genesis doc.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not actually sure about passing GenesisDoc via a factory method (i.e. GenesisDocProvider). Almost by definition GenesisDoc creation is point-like and immutable, but a factory method implies it that it may need to created multiple times, lazily initialised, or icreated n different contexts that branch. None of these should be true for genesis. I think it would be better to make NewNode take a plain GenesisDoc as a argument (value type to emphasise the immutability.) Callers will just need to call your default provider rather than passing it. All I do for the provider is the busywork of wrapping my GenesisDoc in a func.

I also think that the GenesisDoc is an interesting part of the audit trail of the chain and you should probbly store it and serve it from state reliably.

Also in the world where we are handing provision of genesis doc and database provider to the caller we shouldn't make assumptions about what state is co-located or not or even stored to disk.

Come to think of it I actually think a hash of the GenesisDoc should be mixed into the initial AppHash. I don't think it's the same chain if it didn't start with the same GenesisDoc and validator set, but I suppose the way you have it now allows for some flexibility for the ABCI app in that respect (in next Burrow the initial AppHash is our GenesisDoc hash which includes validator set and time, ChainID is also derived from that)

Copy link
Contributor

Choose a reason for hiding this comment

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

wow, thanks for your input! ok, let's persist genesis doc

Copy link
Contributor

Choose a reason for hiding this comment

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

As for NewNode taking GenesisDoc as an argument, don't think this is what we want in the end. We call genesisDocProvider only once, then we save genesis doc to the state. If we rewrite the code to allow to pass it as an argument, this would mean the caller would have to retrieve it from some source on every start and that's not what we want.

Copy link
Contributor

@ebuchman ebuchman Oct 17, 2017

Choose a reason for hiding this comment

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

what if we change the DBProvider to an interface:

type DBProvider interface{
  DB(*DBContext) (dbm.DB, error)
  GenesisDoc() GenesisDoc
}

then we can remove the genesisDocProvider, and folks can wrap up their strategies for genesis files and dbs however they want

Copy link
Contributor

Choose a reason for hiding this comment

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

meh, this is kinda weird.

Ok I think what we currently have is fine. Let's let it lie for a bit until something genuinely better emerges.

node/node.go Outdated
}
state.Save()
} else {
state.SetChainID(genDoc.ChainID)
Copy link
Contributor

Choose a reason for hiding this comment

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

right - we shouldn't have a need for this (but I see this is why the genesis was moved out of the if block. The chainID should be saved somewhere. The ConsensusParams may also change over the life of the chain (not implemented yet), so we don't want to set them back to the genesis params every time we start

node/node.go Outdated

// reload the state (it may have been updated by the handshake)
state = sm.LoadState(stateDB)
state.SetChainID(genDoc.ChainID)
Copy link
Contributor

Choose a reason for hiding this comment

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

see above

state/state.go Outdated
// should not change
GenesisDoc *types.GenesisDoc
ChainID string
// See https://github.com/tendermint/tendermint/issues/671.
Copy link
Contributor

Choose a reason for hiding this comment

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

I know Jae doesn't like private mutable data fields in the State. We may need to seek another way to do this ... perhaps the params need to live in the ConsensusState.

Immutable private chainID should be ok.

Copy link
Contributor

Choose a reason for hiding this comment

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

perhaps the params need to live in the ConsensusState.

Will these params always be for consensus only (maybe we'll want to add blockchain params or something?).

Copy link
Contributor

Choose a reason for hiding this comment

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

Also, if I am not mistaken, we do not persist ConsensusState (as we recreate it using blockstore & WAL). So, how about we store ChainID & Params under a separate key (genesisParamsKey)?

Copy link
Contributor

Choose a reason for hiding this comment

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

Ok, I think we should just expose ChainID and Params in here and let them be written every time too.

I'd ask @jaekwon to confirm.

Also if we will want historical params like we have historical validators once we update ABCI to allow changes there.

It would also be amazing if state encoding was extensible so we dont have a breaking change every time we want to change something here!

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah we should definitely expose ChainID.
ConsensusParams is small enough, we can just write it.

state/state.go Outdated
}
state.Save()
} else {
state.SetChainID(genDoc.ChainID)
Copy link
Contributor

Choose a reason for hiding this comment

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

see above

state/state.go Outdated

// SetChainID sets the chain ID.
func (s *State) SetChainID(chainID string) {
s.chainID = chainID
Copy link
Contributor

Choose a reason for hiding this comment

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

eh. Maybe it's fine if ChainID is written to disk every time - it's small, and might be worth avoiding this extra step of needing to set it. I can see folks easily forgetting to call this, and everything will probably break without it.

// create list of them
pubkeys := make([]crypto.PubKey, N+1)
pubkeys[0] = state.GenesisDoc.Validators[0].PubKey
_, val := state.Validators.GetByIndex(0)
Copy link
Contributor

Choose a reason for hiding this comment

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

++

@ebuchman
Copy link
Contributor

ebuchman commented Oct 6, 2017

This change probably warrants more discussion.

Why is it needed for #564 ?

They should probably come together since both breaking changes to state. However #564 is something we can do easily, though it's breaking, while this is a bigger change.

Question is do we want to rapid fire a series of breaking changes as we iterate through some refactoring here, or should we try to bundle them at lower frequency ...

@melekes
Copy link
Contributor

melekes commented Oct 6, 2017

Why is it needed for #564 ?

because including map[string]interface{} (for holding app_options) into GenesisDoc causing State to crash while attempting to save itself (you probably already know why - go-wire).

@ebuchman
Copy link
Contributor

ebuchman commented Oct 6, 2017

Oh I was thinking to use json.RawMessage to avoid that! It's not like we actually need access to the app_options, just to print them!

@melekes
Copy link
Contributor

melekes commented Oct 6, 2017

Oh I was thinking to use json.RawMessage to avoid that!

oh, my bad then. will push the code shortly.

@melekes melekes self-assigned this Oct 6, 2017
state/state.go Outdated
defer s.mtx.Unlock()
s.saveValidatorsInfo()
s.db.SetSync(stateKey, s.Bytes())
s.mtx.Unlock()
Copy link
Contributor

Choose a reason for hiding this comment

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

I prefer defer s.mtx.Unlock() unless there's something to do after unlocking.

melekes added a commit that referenced this pull request Oct 12, 2017
```
jaekwon
Yeah we should definitely expose ChainID.
ConsensusParams is small enough, we can just write it.
```
#676 (comment)
@melekes melekes force-pushed the state-unexpose-genesisDoc-chainID branch from 608d175 to 2eba353 Compare October 12, 2017 11:04
melekes added a commit that referenced this pull request Oct 12, 2017
```
jaekwon
Yeah we should definitely expose ChainID.
ConsensusParams is small enough, we can just write it.
```
#676 (comment)
@melekes melekes removed the request for review from adrianbrink October 12, 2017 11:08
Copy link
Contributor

@ebuchman ebuchman left a comment

Choose a reason for hiding this comment

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

Tentative approval but see comments/questions

state/state.go Outdated
ChainID string
// consensus parameters used for validating blocks
// must not be nil
Params *types.ConsensusParams
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need the pointer ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

GenesisDoc uses a pointer value https://github.com/tendermint/tendermint/pull/676/files/2eba353e2ed3da4c1ae18b4bde3e7f853a7a66a3#diff-f6be34387a141f652301c16cf7a5e36cL272 so that's just transferring the field in here. However, to answer your question, usually I'll go with pointers because then I can find out if something was set or not idiomatically with

if g.Params == nil {
}

as opposed to

if g.Params == types.ConsensusParams{} {
}

or

if reflect.DeepEqual(g.Params, types.ConsensusParams{}) {
}

Copy link
Contributor

Choose a reason for hiding this comment

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

I think it depends on how often params will be changing. If not very often, we can make it a raw struct. If the opposite, then making it a pointer makes sense for faster updates.

state/state.go Outdated
// should not change
GenesisDoc *types.GenesisDoc
ChainID string
// See https://github.com/tendermint/tendermint/issues/671.
Copy link
Contributor

Choose a reason for hiding this comment

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

we can remove this comment now

node/node.go Outdated
return nil, err
}

genDoc, err := genesisDocProvider()
Copy link
Contributor

Choose a reason for hiding this comment

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

If we start a node, and then later the genesis file is changed, we will not be able to restart the node unless we can recover that genesis file. So I think it's worth having the genesis saved in the database to prevent a certain class of user errors. What do you think?

odeke-em and others added 5 commits October 16, 2017 10:34
…thods

Fixes #671

Unexpose GenesisDoc and ChainID fields to avoid them being
serialized to the DB on every block write/state.Save()

A GenesisDoc can now be alternatively written to the state's
database, by serializing its JSON as a value of key "genesis-doc".

There are now accessors and a setter for these attributes:
- state.GenesisDoc() (*types.GenesisDoc, error)
- state.ChainID() (string, error)
- state.SetGenesisDoc(*types.GenesisDoc)

This is a breaking change since it changes how the state's
serialization and requires that if loading the GenesisDoc entirely
from the database, you'll need to set its value in the database
as the GenesisDoc's JSON marshaled bytes.
- remove state#GenesisDoc() method
```
jaekwon
Yeah we should definitely expose ChainID.
ConsensusParams is small enough, we can just write it.
```
#676 (comment)
also remove the comment
@melekes melekes force-pushed the state-unexpose-genesisDoc-chainID branch from 87c52ba to 6469e2c Compare October 16, 2017 06:52
return nil, errors.New("Genesis doc not found")
} else {
var genDoc *types.GenesisDoc
err := json.Unmarshal(bytes, &genDoc)
Copy link
Contributor

Choose a reason for hiding this comment

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

maybe we panic here actually?

Copy link
Contributor

Choose a reason for hiding this comment

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

you're right

Copy link
Contributor

Choose a reason for hiding this comment

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

also the double pointer here can be confusing. Isn't it better to:

genDoc := new(types.GenesisDoc)
Unmarshal(bytes, genDoc)

?

Copy link
Contributor

Choose a reason for hiding this comment

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

mm.. using *smth seems more standard. I am not used to using new

@ebuchman ebuchman merged commit fa56e8c into develop Oct 19, 2017
@ebuchman ebuchman deleted the state-unexpose-genesisDoc-chainID branch October 19, 2017 00:10
cmwaters pushed a commit to cmwaters/tendermint that referenced this pull request Dec 12, 2022
firelizzard18 pushed a commit to AccumulateNetwork/tendermint that referenced this pull request Feb 1, 2024
…ndermint#676)

Bumps [bufbuild/buf-setup-action](https://github.com/bufbuild/buf-setup-action) from 1.16.0 to 1.17.0.
- [Release notes](https://github.com/bufbuild/buf-setup-action/releases)
- [Commits](bufbuild/buf-setup-action@v1.16.0...v1.17.0)

---
updated-dependencies:
- dependency-name: bufbuild/buf-setup-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants