Skip to content

Commit

Permalink
Merge pull request #45 from line/feature/proof_in_block
Browse files Browse the repository at this point in the history
feat: store proof, round on block
  • Loading branch information
Woosang Son authored Apr 2, 2020
2 parents 55b8f34 + 7fa8319 commit 0168be6
Show file tree
Hide file tree
Showing 22 changed files with 236 additions and 60 deletions.
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

0 comments on commit 0168be6

Please sign in to comment.