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

feat: store proof, round on block #45

Merged
merged 9 commits into from
Apr 2, 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
5 changes: 5 additions & 0 deletions CHANGELOG_PENDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,12 @@ program](https://hackerone.com/tendermint).

- Go API

- Blockchain Protocol

- [state] [\#7](https://github.com/line/tendermint/issues/7) Add round, proof in block

### FEATURES:
- [types] [\#40](https://github.com/line/tendermint/issues/40) Add vrf interface and add a function generating vrf proof to PrivValidator

### IMPROVEMENTS:

Expand Down
8 changes: 5 additions & 3 deletions blockchain/v0/reactor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ func newBlockchainReactor(
lastBlockMeta.BlockID, []types.CommitSig{vote.CommitSig()})
}

thisBlock := makeBlock(blockHeight, state, lastCommit)
thisBlock := makeBlock(privVals[0], blockHeight, state, lastCommit)

thisParts := thisBlock.MakePartSet(types.BlockPartSizeBytes)
blockID := types.BlockID{Hash: thisBlock.Hash(), PartsHeader: thisParts.Header()}
Expand Down Expand Up @@ -345,8 +345,10 @@ func makeTxs(height int64) (txs []types.Tx) {
return txs
}

func makeBlock(height int64, state sm.State, lastCommit *types.Commit) *types.Block {
block, _ := state.MakeBlock(height, makeTxs(height), lastCommit, nil, state.Validators.GetProposer().Address)
func makeBlock(privVal types.PrivValidator, height int64, state sm.State, lastCommit *types.Commit) *types.Block {
message, _ := state.MakeHashMessage(0)
proof, _ := privVal.GenerateVRFProof(message)
block, _ := state.MakeBlock(height, makeTxs(height), lastCommit, nil, state.Validators.GetProposer().Address, 0, proof)
return block
}

Expand Down
8 changes: 5 additions & 3 deletions blockchain/v1/reactor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ func newBlockchainReactor(
lastCommit = types.NewCommit(vote.Height, vote.Round, lastBlockMeta.BlockID, []types.CommitSig{vote.CommitSig()})
}

thisBlock := makeBlock(blockHeight, state, lastCommit)
thisBlock := makeBlock(privVals[0], blockHeight, state, lastCommit)

thisParts := thisBlock.MakePartSet(types.BlockPartSizeBytes)
blockID := types.BlockID{Hash: thisBlock.Hash(), PartsHeader: thisParts.Header()}
Expand Down Expand Up @@ -419,8 +419,10 @@ func makeTxs(height int64) (txs []types.Tx) {
return txs
}

func makeBlock(height int64, state sm.State, lastCommit *types.Commit) *types.Block {
block, _ := state.MakeBlock(height, makeTxs(height), lastCommit, nil, state.Validators.GetProposer().Address)
func makeBlock(privVal types.PrivValidator, height int64, state sm.State, lastCommit *types.Commit) *types.Block {
message, _ := state.MakeHashMessage(0)
proof, _ := privVal.GenerateVRFProof(message)
block, _ := state.MakeBlock(height, makeTxs(height), lastCommit, nil, state.Validators.GetProposer().Address, 0, proof)
return block
}

Expand Down
4 changes: 2 additions & 2 deletions consensus/byzantine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,15 +176,15 @@ func byzantineDecideProposalFunc(t *testing.T, height int64, round int, cs *Stat
// Avoid sending on internalMsgQueue and running consensus state.

// Create a new proposal block from state/txs from the mempool.
block1, blockParts1 := cs.createProposalBlock()
block1, blockParts1 := cs.createProposalBlock(round)
polRound, propBlockID := cs.ValidRound, types.BlockID{Hash: block1.Hash(), PartsHeader: blockParts1.Header()}
proposal1 := types.NewProposal(height, round, polRound, propBlockID)
if err := cs.privValidator.SignProposal(cs.state.ChainID, proposal1); err != nil {
t.Error(err)
}

// Create a new proposal block from state/txs from the mempool.
block2, blockParts2 := cs.createProposalBlock()
block2, blockParts2 := cs.createProposalBlock(round)
polRound, propBlockID = cs.ValidRound, types.BlockID{Hash: block2.Hash(), PartsHeader: blockParts2.Header()}
proposal2 := types.NewProposal(height, round, polRound, propBlockID)
if err := cs.privValidator.SignProposal(cs.state.ChainID, proposal2); err != nil {
Expand Down
2 changes: 1 addition & 1 deletion consensus/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ func decideProposal(
round int,
) (proposal *types.Proposal, block *types.Block) {
cs1.mtx.Lock()
block, blockParts := cs1.createProposalBlock()
block, blockParts := cs1.createProposalBlock(round)
validRound := cs1.ValidRound
chainID := cs1.state.ChainID
cs1.mtx.Unlock()
Expand Down
12 changes: 7 additions & 5 deletions consensus/replay_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ func TestSimulateValidatorsChange(t *testing.T) {
newValidatorTx1 := kvstore.MakeValSetChangeTx(valPubKey1ABCI, testMinPower)
err := assertMempool(css[0].txNotifier).CheckTx(newValidatorTx1, nil, mempl.TxInfo{})
assert.Nil(t, err)
propBlock, _ := css[0].createProposalBlock() //changeProposer(t, cs1, vs2)
propBlock, _ := css[0].createProposalBlock(0) //changeProposer(t, cs1, vs2)
propBlockParts := propBlock.MakePartSet(partSize)
blockID := types.BlockID{Hash: propBlock.Hash(), PartsHeader: propBlockParts.Header()}
proposal := types.NewProposal(vss[1].Height, round, -1, blockID)
Expand All @@ -374,7 +374,7 @@ func TestSimulateValidatorsChange(t *testing.T) {
updateValidatorTx1 := kvstore.MakeValSetChangeTx(updatePubKey1ABCI, 25)
err = assertMempool(css[0].txNotifier).CheckTx(updateValidatorTx1, nil, mempl.TxInfo{})
assert.Nil(t, err)
propBlock, _ = css[0].createProposalBlock() //changeProposer(t, cs1, vs2)
propBlock, _ = css[0].createProposalBlock(0) //changeProposer(t, cs1, vs2)
propBlockParts = propBlock.MakePartSet(partSize)
blockID = types.BlockID{Hash: propBlock.Hash(), PartsHeader: propBlockParts.Header()}
proposal = types.NewProposal(vss[2].Height, round, -1, blockID)
Expand Down Expand Up @@ -404,7 +404,7 @@ func TestSimulateValidatorsChange(t *testing.T) {
newValidatorTx3 := kvstore.MakeValSetChangeTx(newVal3ABCI, testMinPower)
err = assertMempool(css[0].txNotifier).CheckTx(newValidatorTx3, nil, mempl.TxInfo{})
assert.Nil(t, err)
propBlock, _ = css[0].createProposalBlock() //changeProposer(t, cs1, vs2)
propBlock, _ = css[0].createProposalBlock(0) //changeProposer(t, cs1, vs2)
propBlockParts = propBlock.MakePartSet(partSize)
blockID = types.BlockID{Hash: propBlock.Hash(), PartsHeader: propBlockParts.Header()}
newVss := make([]*validatorStub, nVals+1)
Expand Down Expand Up @@ -462,7 +462,7 @@ func TestSimulateValidatorsChange(t *testing.T) {
removeValidatorTx3 := kvstore.MakeValSetChangeTx(newVal3ABCI, 0)
err = assertMempool(css[0].txNotifier).CheckTx(removeValidatorTx3, nil, mempl.TxInfo{})
assert.Nil(t, err)
propBlock, _ = css[0].createProposalBlock() //changeProposer(t, cs1, vs2)
propBlock, _ = css[0].createProposalBlock(0) //changeProposer(t, cs1, vs2)
propBlockParts = propBlock.MakePartSet(partSize)
blockID = types.BlockID{Hash: propBlock.Hash(), PartsHeader: propBlockParts.Header()}
newVss = make([]*validatorStub, nVals+3)
Expand Down Expand Up @@ -897,7 +897,9 @@ func makeBlock(state sm.State, lastBlock *types.Block, lastBlockMeta *types.Bloc
lastBlockMeta.BlockID, []types.CommitSig{vote.CommitSig()})
}

return state.MakeBlock(height, []types.Tx{}, lastCommit, nil, state.Validators.GetProposer().Address)
message, _ := state.MakeHashMessage(0)
proof, _ := privVal.GenerateVRFProof(message)
return state.MakeBlock(height, []types.Tx{}, lastCommit, nil, state.Validators.GetProposer().Address, 0, proof)
}

type badApp struct {
Expand Down
26 changes: 17 additions & 9 deletions consensus/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"time"

"github.com/pkg/errors"

"github.com/tendermint/tendermint/libs/fail"
"github.com/tendermint/tendermint/libs/log"
tmos "github.com/tendermint/tendermint/libs/os"
Expand Down Expand Up @@ -899,7 +898,6 @@ func (cs *State) enterPropose(height int64, round int) {
return
}
logger.Info(fmt.Sprintf("enterPropose(%v/%v). Current: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))

defer func() {
// Done enterPropose:
cs.updateRoundStep(round, cstypes.RoundStepPropose)
Expand Down Expand Up @@ -960,7 +958,7 @@ func (cs *State) defaultDecideProposal(height int64, round int) {
block, blockParts = cs.ValidBlock, cs.ValidBlockParts
} else {
// Create a new proposal block from state/txs from the mempool.
block, blockParts = cs.createProposalBlock()
block, blockParts = cs.createProposalBlock(round)
if block == nil { // on error
return
}
Expand Down Expand Up @@ -1009,7 +1007,7 @@ func (cs *State) isProposalComplete() bool {
// is returned for convenience so we can log the proposal block.
// Returns nil block upon error.
// NOTE: keep it side-effect free for clarity.
func (cs *State) createProposalBlock() (block *types.Block, blockParts *types.PartSet) {
func (cs *State) createProposalBlock(round int) (block *types.Block, blockParts *types.PartSet) {
var commit *types.Commit
switch {
case cs.Height == 1:
Expand All @@ -1026,7 +1024,18 @@ func (cs *State) createProposalBlock() (block *types.Block, blockParts *types.Pa
}

proposerAddr := cs.privValidator.GetPubKey().Address()
return cs.blockExec.CreateProposalBlock(cs.Height, cs.state, commit, proposerAddr)
message, err := cs.state.MakeHashMessage(round)
if err != nil {
cs.Logger.Error("enterPropose: Cannot generate vrf message: %s", err.Error())
return
}

proof, err := cs.privValidator.GenerateVRFProof(message)
if err != nil {
cs.Logger.Error("enterPropose: Cannot generate vrf proof: %s", err.Error())
return
}
return cs.blockExec.CreateProposalBlock(cs.Height, cs.state, commit, proposerAddr, round, proof)
}

// Enter: `timeoutPropose` after entering Propose.
Expand Down Expand Up @@ -1078,7 +1087,7 @@ func (cs *State) defaultDoPrevote(height int64, round int) {
}

// Validate proposal block
err := cs.blockExec.ValidateBlock(cs.state, cs.ProposalBlock)
err := cs.blockExec.ValidateBlock(cs.state, round, cs.ProposalBlock)
if err != nil {
// ProposalBlock is invalid, prevote nil.
logger.Error("enterPrevote: ProposalBlock is invalid", "err", err)
Expand Down Expand Up @@ -1203,7 +1212,7 @@ func (cs *State) enterPrecommit(height int64, round int) {
if cs.ProposalBlock.HashesTo(blockID.Hash) {
logger.Info("enterPrecommit: +2/3 prevoted proposal block. Locking", "hash", blockID.Hash)
// Validate the block.
if err := cs.blockExec.ValidateBlock(cs.state, cs.ProposalBlock); err != nil {
if err := cs.blockExec.ValidateBlock(cs.state, round, cs.ProposalBlock); err != nil {
panic(fmt.Sprintf("enterPrecommit: +2/3 prevoted for an invalid block: %v", err))
}
cs.LockedRound = round
Expand Down Expand Up @@ -1374,7 +1383,7 @@ func (cs *State) finalizeCommit(height int64) {
if !block.HashesTo(blockID.Hash) {
panic(fmt.Sprintf("Cannot finalizeCommit, ProposalBlock does not hash to commit hash"))
}
if err := cs.blockExec.ValidateBlock(cs.state, block); err != nil {
if err := cs.blockExec.ValidateBlock(cs.state, cs.CommitRound, block); err != nil {
panic(fmt.Sprintf("+2/3 committed an invalid block: %v", err))
}

Expand Down Expand Up @@ -1448,7 +1457,6 @@ func (cs *State) finalizeCommit(height int64) {

// NewHeightStep!
cs.updateToState(stateCopy)

fail.Fail() // XXX

// cs.StartTime is already set.
Expand Down
2 changes: 1 addition & 1 deletion consensus/state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ func TestStateBadProposal(t *testing.T) {
proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal)
voteCh := subscribe(cs1.eventBus, types.EventQueryVote)

propBlock, _ := cs1.createProposalBlock() //changeProposer(t, cs1, vs2)
propBlock, _ := cs1.createProposalBlock(round) //changeProposer(t, cs1, vs2)

// make the second validator the proposer by incrementing round
round++
Expand Down
16 changes: 12 additions & 4 deletions node/node_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ func TestCreateProposalBlock(t *testing.T) {
logger := log.TestingLogger()

var height int64 = 1
state, stateDB := state(1, height)
state, stateDB, privVal := state(1, height)
maxBytes := 16384
state.ConsensusParams.Block.MaxBytes = int64(maxBytes)
proposerAddr, _ := state.Validators.GetByIndex(0)
Expand Down Expand Up @@ -280,13 +280,17 @@ func TestCreateProposalBlock(t *testing.T) {
)

commit := types.NewCommit(height-1, 0, types.BlockID{}, nil)
message, _ := state.MakeHashMessage(0)
proof, _ := privVal.GenerateVRFProof(message)
block, _ := blockExec.CreateProposalBlock(
height,
state, commit,
proposerAddr,
0,
proof,
)

err = blockExec.ValidateBlock(state, block)
err = blockExec.ValidateBlock(state, 0, block)
assert.NoError(t, err)
}

Expand Down Expand Up @@ -323,11 +327,15 @@ func TestNodeNewNodeCustomReactors(t *testing.T) {
assert.Equal(t, customBlockchainReactor, n.Switch().Reactor("BLOCKCHAIN"))
}

func state(nVals int, height int64) (sm.State, dbm.DB) {
func state(nVals int, height int64) (sm.State, dbm.DB, types.PrivValidator) {
vals := make([]types.GenesisValidator, nVals)
var privVal types.PrivValidator
for i := 0; i < nVals; i++ {
secret := []byte(fmt.Sprintf("test%d", i))
pk := ed25519.GenPrivKeyFromSecret(secret)
if privVal == nil {
privVal = types.NewMockPVWithParams(pk, false, false)
}
vals[i] = types.GenesisValidator{
Address: pk.PubKey().Address(),
PubKey: pk.PubKey(),
Expand All @@ -350,5 +358,5 @@ func state(nVals int, height int64) (sm.State, dbm.DB) {
s.LastValidators = s.Validators.Copy()
sm.SaveState(stateDB, s)
}
return s, stateDB
return s, stateDB, privVal
}
3 changes: 1 addition & 2 deletions privval/signer_requestHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,7 @@ func DefaultValidationRequestHandler(
}

case *VRFProofRequest:
message := r.Message
proof, err := privVal.GenerateVRFProof(message)
proof, err := privVal.GenerateVRFProof(r.Message)
if err != nil {
res = &VRFProofResponse{nil, &RemoteSignerError{0, err.Error()}}
} else {
Expand Down
14 changes: 10 additions & 4 deletions state/execution.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"time"

abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto/vrf"
"github.com/tendermint/tendermint/libs/fail"
"github.com/tendermint/tendermint/libs/log"
mempl "github.com/tendermint/tendermint/mempool"
Expand Down Expand Up @@ -92,6 +93,8 @@ func (blockExec *BlockExecutor) CreateProposalBlock(
height int64,
state State, commit *types.Commit,
proposerAddr []byte,
round int,
proof vrf.Proof,
) (*types.Block, *types.PartSet) {

maxBytes := state.ConsensusParams.Block.MaxBytes
Expand All @@ -105,15 +108,15 @@ func (blockExec *BlockExecutor) CreateProposalBlock(
maxDataBytes := types.MaxDataBytes(maxBytes, state.Validators.Size(), len(evidence))
txs := blockExec.mempool.ReapMaxBytesMaxGas(maxDataBytes, maxGas)

return state.MakeBlock(height, txs, commit, evidence, proposerAddr)
return state.MakeBlock(height, txs, commit, evidence, proposerAddr, round, proof)
}

// ValidateBlock validates the given block against the given state.
// If the block is invalid, it returns an error.
// Validation does not mutate state, but does require historical information from the stateDB,
// ie. to verify evidence from a validator at an old height.
func (blockExec *BlockExecutor) ValidateBlock(state State, block *types.Block) error {
return validateBlock(blockExec.evpool, blockExec.db, state, block)
func (blockExec *BlockExecutor) ValidateBlock(state State, round int, block *types.Block) error {
return validateBlock(blockExec.evpool, blockExec.db, state, round, block)
}

// ApplyBlock validates the block against the state, executes it against the app,
Expand All @@ -123,7 +126,9 @@ func (blockExec *BlockExecutor) ValidateBlock(state State, block *types.Block) e
// It takes a blockID to avoid recomputing the parts hash.
func (blockExec *BlockExecutor) ApplyBlock(state State, blockID types.BlockID, block *types.Block) (State, error) {

if err := blockExec.ValidateBlock(state, block); err != nil {
// When doing ApplyBlock, we don't need to check whether the block.Round is same to current round,
// so we just put block.Round for the current round parameter
if err := blockExec.ValidateBlock(state, block.Round, block); err != nil {
return state, ErrInvalidBlock(err)
}

Expand Down Expand Up @@ -430,6 +435,7 @@ func updateState(
LastBlockHeight: header.Height,
LastBlockID: blockID,
LastBlockTime: header.Time,
LastProof: header.Proof.Bytes(),
NextValidators: nValSet,
Validators: state.NextValidators.Copy(),
LastValidators: state.Validators.Copy(),
Expand Down
Loading