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

Add ProofHash for first block #51

Merged
merged 6 commits into from
Apr 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -402,9 +402,7 @@ workflows:
only:
- docs-theme-latest
- lint
- setup_dependencies:
requires:
- lint
- setup_dependencies
- test_abci_apps:
requires:
- setup_dependencies
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG_PENDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ program](https://hackerone.com/tendermint).
### FEATURES:
- [types] [\#40](https://github.com/line/tendermint/issues/40) Add vrf interface and add a function generating vrf proof to PrivValidator
- [lib/rand] [\#43](https://github.com/line/tendermint/issues/43) Implementation of selection algorithms using categorical distributions
- [state] [\#44](https://github.com/line/tendermint/issues/44) Add genesis seed for electing proposer of first block

### IMPROVEMENTS:

Expand Down
8 changes: 7 additions & 1 deletion state/execution.go
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,12 @@ func updateState(
// TODO: allow app to upgrade version
nextVersion := state.Version

// get proof hash from vrf proof
proofHash, err := vrf.ProofToHash(header.Proof.Bytes())
if err != nil {
return state, fmt.Errorf("error get proof of hash: %v", err)
}

// NOTE: the AppHash has not been populated.
// It will be filled on state.Save.
return State{
Expand All @@ -435,7 +441,7 @@ func updateState(
LastBlockHeight: header.Height,
LastBlockID: blockID,
LastBlockTime: header.Time,
LastProof: header.Proof.Bytes(),
LastProofHash: proofHash,
NextValidators: nValSet,
Validators: state.NextValidators.Copy(),
LastValidators: state.Validators.Copy(),
Expand Down
7 changes: 4 additions & 3 deletions state/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ func makeAndCommitGoodBlock(
privVals map[string]types.PrivValidator,
evidence []types.Evidence) (sm.State, types.BlockID, *types.Commit, error) {
// A good block passes
state, blockID, err := makeAndApplyGoodBlock(state, privVals[state.Validators.Proposer.Address.String()], height, lastCommit, proposerAddr, blockExec, evidence)
state, blockID, err := makeAndApplyGoodBlock(state, privVals[state.Validators.Proposer.Address.String()], height,
lastCommit, proposerAddr, blockExec, evidence)
if err != nil {
return state, types.BlockID{}, nil, err
}
Expand All @@ -58,8 +59,8 @@ func makeAndCommitGoodBlock(
return state, blockID, commit, nil
}

func makeAndApplyGoodBlock(state sm.State, privVal types.PrivValidator, height int64, lastCommit *types.Commit, proposerAddr []byte,
blockExec *sm.BlockExecutor, evidence []types.Evidence) (sm.State, types.BlockID, error) {
func makeAndApplyGoodBlock(state sm.State, privVal types.PrivValidator, height int64, lastCommit *types.Commit,
proposerAddr []byte, blockExec *sm.BlockExecutor, evidence []types.Evidence) (sm.State, types.BlockID, error) {
message, _ := state.MakeHashMessage(0)
proof, _ := privVal.GenerateVRFProof(message)
block, _ := state.MakeBlock(height, makeTxs(height), lastCommit, evidence, proposerAddr, 0, proof)
Expand Down
24 changes: 6 additions & 18 deletions state/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ type State struct {
LastBlockID types.BlockID
LastBlockTime time.Time

// vrf proof
LastProof vrf.Proof
// vrf hash from proof
LastProofHash []byte

// LastValidators is used to validate block.LastCommit.
// Validators are persisted to the database separately every time they change,
Expand All @@ -89,23 +89,11 @@ type State struct {
}

func (state State) MakeHashMessage(round int) ([]byte, error) {
var seed []byte

if len(state.LastProof) == 0 {
// TODO: This code is temporary. When genesis seed is prepared, use that code.
seed = []byte("LINE Blockchain VRF Algorithm's first seed")
} else {
output, err := vrf.ProofToHash(state.LastProof)
if err != nil {
return nil, err
}
seed = output
}
b := make([]byte, 16)
binary.LittleEndian.PutUint64(b, uint64(state.LastBlockHeight))
binary.LittleEndian.PutUint64(b[8:], uint64(round))
hash := tmhash.New()
hash.Write(seed)
hash.Write(state.LastProofHash)
return hash.Sum(b), nil
}

Expand All @@ -119,7 +107,7 @@ func (state State) Copy() State {
LastBlockID: state.LastBlockID,
LastBlockTime: state.LastBlockTime,

LastProof: state.LastProof,
LastProofHash: state.LastProofHash,

NextValidators: state.NextValidators.Copy(),
Validators: state.Validators.Copy(),
Expand Down Expand Up @@ -271,8 +259,8 @@ func MakeGenesisState(genDoc *types.GenesisDoc) (State, error) {
LastBlockID: types.BlockID{},
LastBlockTime: genDoc.GenesisTime,

// genesis block has no last proof
LastProof: nil,
// genesis block use the hash of GenesisDoc instead for the `LastProofHash`
LastProofHash: genDoc.Hash(),

NextValidators: nextValidatorSet,
Validators: validatorSet,
Expand Down
5 changes: 4 additions & 1 deletion state/state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto/ed25519"
"github.com/tendermint/tendermint/crypto/vrf"
"github.com/tendermint/tendermint/libs/kv"
"github.com/tendermint/tendermint/libs/rand"
tmrand "github.com/tendermint/tendermint/libs/rand"
Expand Down Expand Up @@ -1027,7 +1028,9 @@ func TestState_MakeHashMessage(t *testing.T) {
require.False(t, bytes.Equal(message1, message2))

privVal := makePrivVal()
state.LastProof, _ = privVal.GenerateVRFProof(message1)
proof, _ := privVal.GenerateVRFProof(message1)
output, _ := vrf.ProofToHash(proof)
state.LastProofHash = output
message3, err := state.MakeHashMessage(0)
require.NoError(t, err)
require.False(t, bytes.Equal(message1, message3))
Expand Down
7 changes: 5 additions & 2 deletions state/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,12 @@ func validateBlock(evidencePool EvidencePool, stateDB dbm.DB, state State, round
_, val := state.Validators.GetByAddress(block.ProposerAddress)
verified, err := vrf.Verify(val.PubKey.(ed25519.PubKeyEd25519), block.Proof.Bytes(), message)
if err != nil {
return types.NewErrInvalidProof(fmt.Sprintf("verification failed: %s; proof: %v, prevProof: %v, height=%d, round=%d, addr: %v", err.Error(), block.Proof, state.LastProof, state.LastBlockHeight, block.Round, block.ProposerAddress))
return types.NewErrInvalidProof(fmt.Sprintf(
"verification failed: %s; proof: %v, prevProofHash: %v, height=%d, round=%d, addr: %v",
err.Error(), block.Proof, state.LastProofHash, state.LastBlockHeight, block.Round, block.ProposerAddress))
} else if !verified {
return types.NewErrInvalidProof(fmt.Sprintf("proof: %v, prevProof: %v, height=%d, round=%d, addr: %v", block.Proof, state.LastProof, state.LastBlockHeight, block.Round, block.ProposerAddress))
return types.NewErrInvalidProof(fmt.Sprintf("proof: %v, prevProofHash: %v, height=%d, round=%d, addr: %v",
block.Proof, state.LastProofHash, state.LastBlockHeight, block.Round, block.ProposerAddress))
}

return nil
Expand Down
2 changes: 1 addition & 1 deletion types/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,4 @@ func NewErrInvalidRound(consensusRound, blockRound int) ErrInvalidRound {

func (e ErrInvalidRound) Error() string {
return fmt.Sprintf("Block round(%d) is mismatched to consensus round(%d)", e.BlockRound, e.ConsensusRound)
}
}
5 changes: 5 additions & 0 deletions types/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@ func (genDoc *GenesisDoc) ValidateAndComplete() error {
return nil
}

// Hash returns the hash of the GenesisDoc
func (genDoc *GenesisDoc) Hash() []byte {
return cdcEncode(genDoc)
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this a deterministic result?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, as far as I know
The cdcEncode function is depends on amino MustMarshalBinaryBare. If the marshal rule is changed, the hash is also changed. And this rule is also used in generating block hash.

}

//------------------------------------------------------------
// Make genesis state from file

Expand Down