Skip to content

Commit

Permalink
add signatures and keys to signed header along with signature verific…
Browse files Browse the repository at this point in the history
…ation in validate method (cosmos#788)

Fixes cosmos#782 cosmos#783 cosmos#784

---------

Co-authored-by: Ganesha Upadhyaya <gupadhyaya@Ganeshas-MacBook-Pro-2.local>
  • Loading branch information
gupadhyaya and Ganesha Upadhyaya authored Mar 24, 2023
1 parent 2728eaf commit 770a9bd
Show file tree
Hide file tree
Showing 12 changed files with 622 additions and 156 deletions.
12 changes: 9 additions & 3 deletions block/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -446,8 +446,6 @@ func (m *Manager) getCommit(header types.Header) (*types.Commit, error) {
return nil, err
}
return &types.Commit{
Height: uint64(header.Height()),
HeaderHash: header.Hash(),
Signatures: []types.Signature{sign},
}, nil
}
Expand All @@ -461,7 +459,7 @@ func (m *Manager) publishBlock(ctx context.Context) error {

// this is a special case, when first block is produced - there is no previous commit
if newHeight == uint64(m.genesis.InitialHeight) {
lastCommit = &types.Commit{Height: height}
lastCommit = &types.Commit{}
} else {
lastCommit, err = m.store.LoadCommit(height)
if err != nil {
Expand Down Expand Up @@ -496,6 +494,14 @@ func (m *Manager) publishBlock(ctx context.Context) error {
// set the commit to current block's signed header
block.SignedHeader.Commit = *commit

// set the validator set using the signer's public key
// TODO(ganesh): need to hook into a module that selects signers
pubKey, err := m.proposerKey.GetPublic().Raw()
if err != nil {
return err
}
block.SignedHeader.Validators = types.ValidatorSet{Validators: []types.Validator{{PublicKey: pubKey}}}

// SaveBlock commits the DB tx
err = m.store.SaveBlock(block, commit)
if err != nil {
Expand Down
8 changes: 4 additions & 4 deletions conv/abci/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func ToABCIBlock(block *types.Block) (*tmtypes.Block, error) {
if err != nil {
return nil, err
}
abciCommit := ToABCICommit(&block.SignedHeader.Commit)
abciCommit := ToABCICommit(&block.SignedHeader.Commit, block.SignedHeader.Header.BaseHeader.Height, block.SignedHeader.Hash())
// This assumes that we have only one signature
if len(abciCommit.Signatures) == 1 {
abciCommit.Signatures[0].ValidatorAddress = block.SignedHeader.Header.ProposerAddress
Expand Down Expand Up @@ -116,12 +116,12 @@ func ToABCIBlockMeta(block *types.Block) (*tmtypes.BlockMeta, error) {
// ToABCICommit converts Rollkit commit into commit format defined by ABCI.
// This function only converts fields that are available in Rollkit commit.
// Other fields (especially ValidatorAddress and Timestamp of Signature) has to be filled by caller.
func ToABCICommit(commit *types.Commit) *tmtypes.Commit {
func ToABCICommit(commit *types.Commit, height uint64, hash types.Hash) *tmtypes.Commit {
tmCommit := tmtypes.Commit{
Height: int64(commit.Height),
Height: int64(height),
Round: 0,
BlockID: tmtypes.BlockID{
Hash: tmbytes.HexBytes(commit.HeaderHash),
Hash: tmbytes.HexBytes(hash),
PartSetHeader: tmtypes.PartSetHeader{},
},
}
Expand Down
2 changes: 1 addition & 1 deletion node/full_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,7 @@ func (c *FullClient) Commit(ctx context.Context, height *int64) (*ctypes.ResultC
if err != nil {
return nil, err
}
commit := abciconv.ToABCICommit(com)
commit := abciconv.ToABCICommit(com, heightValue, b.SignedHeader.Hash())
block, err := abciconv.ToABCIBlock(b)
if err != nil {
return nil, err
Expand Down
16 changes: 5 additions & 11 deletions node/full_client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ func TestGetCommit(t *testing.T) {
require.NoError(err)

for _, b := range blocks {
err = rpc.node.Store.SaveBlock(b, &types.Commit{Height: uint64(b.SignedHeader.Header.Height())})
err = rpc.node.Store.SaveBlock(b, &types.Commit{})
rpc.node.Store.SetHeight(uint64(b.SignedHeader.Header.Height()))
require.NoError(err)
}
Expand Down Expand Up @@ -308,10 +308,7 @@ func TestBlockSearch(t *testing.T) {
heights := []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
for _, h := range heights {
block := getRandomBlock(uint64(h), 5)
err := rpc.node.Store.SaveBlock(block, &types.Commit{
Height: uint64(h),
HeaderHash: block.SignedHeader.Header.Hash(),
})
err := rpc.node.Store.SaveBlock(block, &types.Commit{})
require.NoError(err)
}
indexBlocks(t, rpc, heights)
Expand Down Expand Up @@ -562,10 +559,7 @@ func TestBlockchainInfo(t *testing.T) {
heights := []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
for _, h := range heights {
block := getRandomBlock(uint64(h), 5)
err := rpc.node.Store.SaveBlock(block, &types.Commit{
Height: uint64(h),
HeaderHash: block.SignedHeader.Header.Hash(),
})
err := rpc.node.Store.SaveBlock(block, &types.Commit{})
rpc.node.Store.SetHeight(uint64(block.SignedHeader.Header.Height()))
require.NoError(err)
}
Expand Down Expand Up @@ -988,12 +982,12 @@ func TestStatus(t *testing.T) {
assert.NotNil(rpc)

earliestBlock := getRandomBlockWithProposer(1, 1, validators[0].Address.Bytes())
err = rpc.node.Store.SaveBlock(earliestBlock, &types.Commit{Height: uint64(earliestBlock.SignedHeader.Header.Height())})
err = rpc.node.Store.SaveBlock(earliestBlock, &types.Commit{})
rpc.node.Store.SetHeight(uint64(earliestBlock.SignedHeader.Header.Height()))
require.NoError(err)

latestBlock := getRandomBlockWithProposer(2, 1, validators[1].Address.Bytes())
err = rpc.node.Store.SaveBlock(latestBlock, &types.Commit{Height: uint64(latestBlock.SignedHeader.Header.Height())})
err = rpc.node.Store.SaveBlock(latestBlock, &types.Commit{})
rpc.node.Store.SetHeight(uint64(latestBlock.SignedHeader.Header.Height()))
require.NoError(err)

Expand Down
17 changes: 11 additions & 6 deletions proto/rollkit/rollkit.proto
Original file line number Diff line number Diff line change
Expand Up @@ -49,24 +49,29 @@ message Header {
// pubkey can't be recovered by the signature (e.g. ed25519).
bytes proposer_address = 10;

// public key of the proposer so we can verify the signature
bytes proposer_public_key = 11;


// Hash of block aggregator set, at a time of block creation
bytes aggregators_hash = 12;
bytes aggregators_hash = 11;

// Chain ID the block belongs to
string chain_id = 13;
string chain_id = 12;
}

message Commit {
repeated bytes signatures = 1;
}

message Validator {
bytes public_key = 1;
}

message ValidatorSet {
repeated Validator validators = 1;
}

message SignedHeader {
Header header = 1;
Commit commit = 2;
ValidatorSet validators = 3;
}

message Data {
Expand Down
2 changes: 1 addition & 1 deletion state/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,7 @@ func (e *BlockExecutor) generateFraudProof(beginBlockRequest *abci.RequestBeginB
}

func (e *BlockExecutor) getLastCommitHash(lastCommit *types.Commit, header *types.Header) []byte {
lastABCICommit := abciconv.ToABCICommit(lastCommit)
lastABCICommit := abciconv.ToABCICommit(lastCommit, header.BaseHeader.Height, header.Hash())
if len(lastCommit.Signatures) == 1 {
lastABCICommit.Signatures[0].ValidatorAddress = e.proposerAddress
lastABCICommit.Signatures[0].Timestamp = header.Time()
Expand Down
54 changes: 48 additions & 6 deletions state/executor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (

abci "github.com/tendermint/tendermint/abci/types"
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/crypto/ed25519"
"github.com/tendermint/tendermint/libs/log"
"github.com/tendermint/tendermint/libs/pubsub/query"
"github.com/tendermint/tendermint/proxy"
Expand Down Expand Up @@ -44,7 +45,16 @@ func doTestCreateBlock(t *testing.T, fraudProofsEnabled bool) {
state := types.State{}
state.ConsensusParams.Block.MaxBytes = 100
state.ConsensusParams.Block.MaxGas = 100000
state.Validators = tmtypes.NewValidatorSet(nil)
vKey := ed25519.GenPrivKey()
validators := []*tmtypes.Validator{
{
Address: vKey.PubKey().Address(),
PubKey: vKey.PubKey(),
VotingPower: int64(100),
ProposerPriority: int64(1),
},
}
state.Validators = tmtypes.NewValidatorSet(validators)

// empty block
block := executor.CreateBlock(1, &types.Commit{}, []byte{}, state)
Expand Down Expand Up @@ -124,10 +134,19 @@ func doTestApplyBlock(t *testing.T, fraudProofsEnabled bool) {
require.NoError(err)
require.NotNil(headerSub)

vKey := ed25519.GenPrivKey()
validators := []*tmtypes.Validator{
{
Address: vKey.PubKey().Address(),
PubKey: vKey.PubKey(),
VotingPower: int64(100),
ProposerPriority: int64(1),
},
}
state := types.State{
NextValidators: tmtypes.NewValidatorSet(nil),
Validators: tmtypes.NewValidatorSet(nil),
LastValidators: tmtypes.NewValidatorSet(nil),
NextValidators: tmtypes.NewValidatorSet(validators),
Validators: tmtypes.NewValidatorSet(validators),
LastValidators: tmtypes.NewValidatorSet(validators),
}
state.InitialHeight = 1
state.LastBlockHeight = 0
Expand All @@ -136,11 +155,23 @@ func doTestApplyBlock(t *testing.T, fraudProofsEnabled bool) {

_ = mpool.CheckTx([]byte{1, 2, 3, 4}, func(r *abci.Response) {}, mempool.TxInfo{})
require.NoError(err)
block := executor.CreateBlock(1, &types.Commit{}, []byte{}, state)
block := executor.CreateBlock(1, &types.Commit{Signatures: []types.Signature{types.Signature([]byte{1, 1, 1})}}, []byte{}, state)
require.NotNil(block)
assert.Equal(int64(1), block.SignedHeader.Header.Height())
assert.Len(block.Data.Txs, 1)

// Update the signature on the block to current from last
headerBytes, _ := block.SignedHeader.Header.MarshalBinary()
sig, _ := vKey.Sign(headerBytes)
block.SignedHeader.Commit = types.Commit{
Signatures: []types.Signature{sig},
}
block.SignedHeader.Validators = types.ValidatorSet{
Validators: []types.Validator{{
PublicKey: vKey.PubKey().Bytes(),
}},
}

newState, resp, err := executor.ApplyBlock(context.Background(), state, block)
require.NoError(err)
require.NotNil(newState)
Expand All @@ -154,11 +185,22 @@ func doTestApplyBlock(t *testing.T, fraudProofsEnabled bool) {
require.NoError(mpool.CheckTx([]byte{5, 6, 7, 8, 9}, func(r *abci.Response) {}, mempool.TxInfo{}))
require.NoError(mpool.CheckTx([]byte{1, 2, 3, 4, 5}, func(r *abci.Response) {}, mempool.TxInfo{}))
require.NoError(mpool.CheckTx(make([]byte, 90), func(r *abci.Response) {}, mempool.TxInfo{}))
block = executor.CreateBlock(2, &types.Commit{}, []byte{}, newState)
block = executor.CreateBlock(2, &types.Commit{Signatures: []types.Signature{types.Signature([]byte{1, 1, 1})}}, []byte{}, newState)
require.NotNil(block)
assert.Equal(int64(2), block.SignedHeader.Header.Height())
assert.Len(block.Data.Txs, 3)

headerBytes, _ = block.SignedHeader.Header.MarshalBinary()
sig, _ = vKey.Sign(headerBytes)
block.SignedHeader.Commit = types.Commit{
Signatures: []types.Signature{sig},
}
block.SignedHeader.Validators = types.ValidatorSet{
Validators: []types.Validator{{
PublicKey: vKey.PubKey().Bytes(),
}},
}

newState, resp, err = executor.ApplyBlock(context.Background(), newState, block)
require.NoError(err)
require.NotNil(newState)
Expand Down
13 changes: 10 additions & 3 deletions types/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,24 @@ type EvidenceData struct {

// Commit contains evidence of block creation.
type Commit struct {
Height uint64
HeaderHash Hash
Signatures []Signature // most of the time this is a single signature
}

type Validator struct {
PublicKey []byte
}

type ValidatorSet struct {
Validators []Validator
}

// SignedHeader combines Header and its Commit.
//
// Used mostly for gossiping.
type SignedHeader struct {
Header
Commit Commit
Commit Commit
Validators ValidatorSet
}

// Signature represents signature of block creator.
Expand Down
Loading

0 comments on commit 770a9bd

Please sign in to comment.