Skip to content

Commit dd5e371

Browse files
Added signed header verification (#1026)
<!-- Please read and fill out this form before submitting your PR. Please make sure you have reviewed our contributors guide before submitting your first PR. --> ## Overview Resolves: #1027, Resolves: #1048 <!-- Please provide an explanation of the PR, including the appropriate context, background, goal, and rationale. If there is an issue with this information, please provide a tl;dr and link the issue. --> ## Checklist <!-- Please complete the checklist to ensure that the PR is ready to be reviewed. IMPORTANT: PRs should be left in Draft until the below checklist is completed. --> - [x] New and updated code has appropriate documentation - [x] New and updated code has new and/or updated testing - [x] Required CI checks are passing - [x] Visual proof for any user facing features like CLI or documentation updates - [x] Linked issues closed with keywords
1 parent 4c951e4 commit dd5e371

15 files changed

Lines changed: 377 additions & 227 deletions

block/manager_test.go

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import (
99
"github.com/libp2p/go-libp2p/core/crypto"
1010
"github.com/stretchr/testify/assert"
1111
"github.com/stretchr/testify/require"
12-
"github.com/tendermint/tendermint/crypto/ed25519"
1312
"github.com/tendermint/tendermint/libs/log"
1413
tmtypes "github.com/tendermint/tendermint/types"
1514

@@ -29,9 +28,9 @@ func TestInitialState(t *testing.T) {
2928
ChainID: "state id",
3029
InitialHeight: 123,
3130
LastBlockHeight: 128,
32-
LastValidators: getRandomValidatorSet(),
33-
Validators: getRandomValidatorSet(),
34-
NextValidators: getRandomValidatorSet(),
31+
LastValidators: types.GetRandomValidatorSet(),
32+
Validators: types.GetRandomValidatorSet(),
33+
NextValidators: types.GetRandomValidatorSet(),
3534
}
3635

3736
ctx := context.Background()
@@ -97,14 +96,3 @@ func getMockDALC(logger log.Logger) da.DataAvailabilityLayerClient {
9796
_ = dalc.Start()
9897
return dalc
9998
}
100-
101-
// copied from store_test.go
102-
func getRandomValidatorSet() *tmtypes.ValidatorSet {
103-
pubKey := ed25519.GenPrivKey().PubKey()
104-
return &tmtypes.ValidatorSet{
105-
Proposer: &tmtypes.Validator{PubKey: pubKey, Address: pubKey.Address()},
106-
Validators: []*tmtypes.Validator{
107-
{PubKey: pubKey, Address: pubKey.Address()},
108-
},
109-
}
110-
}

conv/abci/block.go

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ func ToABCIBlock(block *types.Block) (*tmtypes.Block, error) {
7676
if err != nil {
7777
return nil, err
7878
}
79-
abciCommit := ToABCICommit(&block.SignedHeader.Commit, block.SignedHeader.Header.BaseHeader.Height, block.SignedHeader.Hash())
79+
abciCommit := block.SignedHeader.Commit.ToABCICommit(int64(block.SignedHeader.Header.BaseHeader.Height), block.SignedHeader.Hash())
8080
// This assumes that we have only one signature
8181
if len(abciCommit.Signatures) == 1 {
8282
abciCommit.Signatures[0].ValidatorAddress = block.SignedHeader.Header.ProposerAddress
@@ -112,26 +112,3 @@ func ToABCIBlockMeta(block *types.Block) (*tmtypes.BlockMeta, error) {
112112
NumTxs: len(tmblock.Txs),
113113
}, nil
114114
}
115-
116-
// ToABCICommit converts Rollkit commit into commit format defined by ABCI.
117-
// This function only converts fields that are available in Rollkit commit.
118-
// Other fields (especially ValidatorAddress and Timestamp of Signature) has to be filled by caller.
119-
func ToABCICommit(commit *types.Commit, height uint64, hash types.Hash) *tmtypes.Commit {
120-
tmCommit := tmtypes.Commit{
121-
Height: int64(height),
122-
Round: 0,
123-
BlockID: tmtypes.BlockID{
124-
Hash: tmbytes.HexBytes(hash),
125-
PartSetHeader: tmtypes.PartSetHeader{},
126-
},
127-
}
128-
for _, sig := range commit.Signatures {
129-
commitSig := tmtypes.CommitSig{
130-
BlockIDFlag: tmtypes.BlockIDFlagCommit,
131-
Signature: sig,
132-
}
133-
tmCommit.Signatures = append(tmCommit.Signatures, commitSig)
134-
}
135-
136-
return &tmCommit
137-
}

da/test/da_test_helpers.go

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package test
22

33
import (
44
"fmt"
5-
"math/rand"
65
"net"
76
"os"
87
"strconv"
@@ -20,17 +19,6 @@ import (
2019

2120
const mockDaBlockTime = 100 * time.Millisecond
2221

23-
func getRandomTx() types.Tx {
24-
size := rand.Int()%100 + 100 //nolint:gosec
25-
return types.Tx(getRandomBytes(size))
26-
}
27-
28-
func getRandomBytes(n int) []byte {
29-
data := make([]byte, n)
30-
_, _ = rand.Read(data) //nolint:gosec
31-
return data
32-
}
33-
3422
// copy-pasted from store/store_test.go
3523
func getRandomBlock(height uint64, nTxs int) *types.Block {
3624
block := &types.Block{
@@ -48,11 +36,11 @@ func getRandomBlock(height uint64, nTxs int) *types.Block {
4836
},
4937
},
5038
}
51-
block.SignedHeader.Header.AppHash = getRandomBytes(32)
39+
block.SignedHeader.Header.AppHash = types.GetRandomBytes(32)
5240

5341
for i := 0; i < nTxs; i++ {
54-
block.Data.Txs[i] = getRandomTx()
55-
block.Data.IntermediateStateRoots.RawRootsList[i] = getRandomBytes(32)
42+
block.Data.Txs[i] = types.GetRandomTx()
43+
block.Data.IntermediateStateRoots.RawRootsList[i] = types.GetRandomBytes(32)
5644
}
5745

5846
// TODO(tzdybal): see https://github.com/rollkit/rollkit/issues/143

node/full_client.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -492,7 +492,7 @@ func (c *FullClient) Commit(ctx context.Context, height *int64) (*ctypes.ResultC
492492
if err != nil {
493493
return nil, err
494494
}
495-
commit := abciconv.ToABCICommit(com, heightValue, b.SignedHeader.Hash())
495+
commit := com.ToABCICommit(int64(heightValue), b.SignedHeader.Hash())
496496
block, err := abciconv.ToABCIBlock(b)
497497
if err != nil {
498498
return nil, err

node/full_client_test.go

Lines changed: 5 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"context"
55
crand "crypto/rand"
66
"fmt"
7-
"math/rand"
87
"sync"
98
"testing"
109
"time"
@@ -45,20 +44,9 @@ var expectedInfo = abci.ResponseInfo{
4544

4645
var mockTxProcessingTime = 10 * time.Millisecond
4746

48-
// TODO: accept argument for number of validators / proposer index
49-
func getRandomValidatorSet() *tmtypes.ValidatorSet {
50-
pubKey := ed25519.GenPrivKey().PubKey()
51-
return &tmtypes.ValidatorSet{
52-
Proposer: &tmtypes.Validator{PubKey: pubKey, Address: pubKey.Address()},
53-
Validators: []*tmtypes.Validator{
54-
{PubKey: pubKey, Address: pubKey.Address()},
55-
},
56-
}
57-
}
58-
5947
// copy-pasted from store/store_test.go
6048
func getRandomBlock(height uint64, nTxs int) *types.Block {
61-
return getRandomBlockWithProposer(height, nTxs, getRandomBytes(20))
49+
return getRandomBlockWithProposer(height, nTxs, types.GetRandomBytes(20))
6250
}
6351

6452
func getRandomBlockWithProposer(height uint64, nTxs int, proposerAddr []byte) *types.Block {
@@ -79,11 +67,11 @@ func getRandomBlockWithProposer(height uint64, nTxs int, proposerAddr []byte) *t
7967
},
8068
},
8169
}
82-
block.SignedHeader.Header.AppHash = getRandomBytes(32)
70+
block.SignedHeader.Header.AppHash = types.GetRandomBytes(32)
8371

8472
for i := 0; i < nTxs; i++ {
85-
block.Data.Txs[i] = getRandomTx()
86-
block.Data.IntermediateStateRoots.RawRootsList[i] = getRandomBytes(32)
73+
block.Data.Txs[i] = types.GetRandomTx()
74+
block.Data.IntermediateStateRoots.RawRootsList[i] = types.GetRandomBytes(32)
8775
}
8876

8977
// TODO(tzdybal): see https://github.com/rollkit/rollkit/issues/143
@@ -100,22 +88,11 @@ func getRandomBlockWithProposer(height uint64, nTxs int, proposerAddr []byte) *t
10088
copy(lastCommitHash, tmprotoLC.Hash().Bytes())
10189
block.SignedHeader.Header.LastCommitHash = lastCommitHash
10290

103-
block.SignedHeader.Validators = getRandomValidatorSet()
91+
block.SignedHeader.Validators = types.GetRandomValidatorSet()
10492

10593
return block
10694
}
10795

108-
func getRandomTx() types.Tx {
109-
size := rand.Int()%100 + 100 //nolint:gosec
110-
return types.Tx(getRandomBytes(size))
111-
}
112-
113-
func getRandomBytes(n int) []byte {
114-
data := make([]byte, n)
115-
_, _ = crand.Read(data)
116-
return data
117-
}
118-
11996
func getBlockMeta(rpc *FullClient, n int64) *tmtypes.BlockMeta {
12097
b, err := rpc.node.Store.LoadBlock(uint64(n))
12198
if err != nil {

state/executor.go

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ func (e *BlockExecutor) CreateBlock(height uint64, lastCommit *types.Commit, las
129129
// Evidence: types.EvidenceData{Evidence: nil},
130130
},
131131
}
132-
block.SignedHeader.Header.LastCommitHash = e.getLastCommitHash(lastCommit, &block.SignedHeader.Header)
132+
block.SignedHeader.Header.LastCommitHash = lastCommit.GetCommitHash(&block.SignedHeader.Header, e.proposerAddress)
133133
block.SignedHeader.Header.LastHeaderHash = lastHeaderHash
134134
block.SignedHeader.Header.AggregatorsHash = state.Validators.Hash()
135135

@@ -475,15 +475,6 @@ func (e *BlockExecutor) generateFraudProof(beginBlockRequest *abci.RequestBeginB
475475
return resp.FraudProof, nil
476476
}
477477

478-
func (e *BlockExecutor) getLastCommitHash(lastCommit *types.Commit, header *types.Header) []byte {
479-
lastABCICommit := abciconv.ToABCICommit(lastCommit, header.BaseHeader.Height, header.Hash())
480-
if len(lastCommit.Signatures) == 1 {
481-
lastABCICommit.Signatures[0].ValidatorAddress = e.proposerAddress
482-
lastABCICommit.Signatures[0].Timestamp = header.Time()
483-
}
484-
return lastABCICommit.Hash()
485-
}
486-
487478
func (e *BlockExecutor) publishEvents(resp *tmstate.ABCIResponses, block *types.Block, state types.State) error {
488479
if e.eventBus == nil {
489480
return nil

store/store_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ func TestStoreLoad(t *testing.T) {
101101
for _, block := range c.blocks {
102102
commit := &types.Commit{}
103103
block.SignedHeader.Commit = *lastCommit
104-
block.SignedHeader.Validators = getRandomValidatorSet()
104+
block.SignedHeader.Validators = types.GetRandomValidatorSet()
105105
err := bstore.SaveBlock(block, commit)
106106
require.NoError(err)
107107
lastCommit = commit
@@ -127,7 +127,7 @@ func TestRestart(t *testing.T) {
127127

128128
assert := assert.New(t)
129129

130-
validatorSet := getRandomValidatorSet()
130+
validatorSet := types.GetRandomValidatorSet()
131131

132132
ctx := context.Background()
133133
kv, _ := NewDefaultInMemoryKVStore()

store/test_helpers.go

Lines changed: 2 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
11
package store
22

33
import (
4-
"math/rand"
5-
6-
"github.com/tendermint/tendermint/crypto/ed25519"
7-
tmtypes "github.com/tendermint/tendermint/types"
8-
94
"github.com/rollkit/rollkit/types"
105
)
116

@@ -27,31 +22,9 @@ func getRandomBlock(height uint64, nTxs int) *types.Block {
2722
}
2823

2924
for i := 0; i < nTxs; i++ {
30-
block.Data.Txs[i] = getRandomTx()
31-
block.Data.IntermediateStateRoots.RawRootsList[i] = getRandomBytes(32)
25+
block.Data.Txs[i] = types.GetRandomTx()
26+
block.Data.IntermediateStateRoots.RawRootsList[i] = types.GetRandomBytes(32)
3227
}
3328

3429
return block
3530
}
36-
37-
func getRandomTx() types.Tx {
38-
size := rand.Int()%100 + 100 //nolint:gosec
39-
return types.Tx(getRandomBytes(size))
40-
}
41-
42-
func getRandomBytes(n int) []byte {
43-
data := make([]byte, n)
44-
_, _ = rand.Read(data) //nolint:gosec
45-
return data
46-
}
47-
48-
// TODO(tzdybal): extract to some common place
49-
func getRandomValidatorSet() *tmtypes.ValidatorSet {
50-
pubKey := ed25519.GenPrivKey().PubKey()
51-
return &tmtypes.ValidatorSet{
52-
Proposer: &tmtypes.Validator{PubKey: pubKey, Address: pubKey.Address()},
53-
Validators: []*tmtypes.Validator{
54-
{PubKey: pubKey, Address: pubKey.Address()},
55-
},
56-
}
57-
}

types/block.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@ package types
22

33
import (
44
"encoding"
5+
"errors"
6+
57
"fmt"
68
"time"
79

10+
tmbytes "github.com/tendermint/tendermint/libs/bytes"
11+
812
"github.com/celestiaorg/go-header"
913
tmtypes "github.com/tendermint/tendermint/types"
1014
)
@@ -65,6 +69,65 @@ type IntermediateStateRoots struct {
6569
RawRootsList [][]byte
6670
}
6771

72+
// ToABCICommit converts Rollkit commit into commit format defined by ABCI.
73+
// This function only converts fields that are available in Rollkit commit.
74+
// Other fields (especially ValidatorAddress and Timestamp of Signature) has to be filled by caller.
75+
func (c *Commit) ToABCICommit(height int64, hash Hash) *tmtypes.Commit {
76+
tmCommit := tmtypes.Commit{
77+
Height: height,
78+
Round: 0,
79+
BlockID: tmtypes.BlockID{
80+
Hash: tmbytes.HexBytes(hash),
81+
PartSetHeader: tmtypes.PartSetHeader{},
82+
},
83+
Signatures: make([]tmtypes.CommitSig, len(c.Signatures)),
84+
}
85+
for i, sig := range c.Signatures {
86+
commitSig := tmtypes.CommitSig{
87+
BlockIDFlag: tmtypes.BlockIDFlagCommit,
88+
Signature: sig,
89+
}
90+
tmCommit.Signatures[i] = commitSig
91+
}
92+
93+
return &tmCommit
94+
}
95+
96+
func (c *Commit) GetCommitHash(header *Header, proposerAddress []byte) []byte {
97+
lastABCICommit := c.ToABCICommit(header.Height(), header.Hash())
98+
// Rollkit does not support a multi signature scheme so there can only be one signature
99+
if len(c.Signatures) == 1 {
100+
lastABCICommit.Signatures[0].ValidatorAddress = proposerAddress
101+
lastABCICommit.Signatures[0].Timestamp = header.Time()
102+
}
103+
return lastABCICommit.Hash()
104+
}
105+
106+
// ValidateBasic performs basic validation of block data.
107+
// Actually it's a placeholder, because nothing is checked.
108+
func (d *Data) ValidateBasic() error {
109+
return nil
110+
}
111+
112+
// ValidateBasic performs basic validation of a commit.
113+
func (c *Commit) ValidateBasic() error {
114+
if len(c.Signatures) == 0 {
115+
return errors.New("no signatures")
116+
}
117+
return nil
118+
}
119+
120+
// ValidateBasic performs basic validation of a block.
121+
func (b *Block) ValidateBasic() error {
122+
if err := b.SignedHeader.ValidateBasic(); err != nil {
123+
return err
124+
}
125+
if err := b.Data.ValidateBasic(); err != nil {
126+
return err
127+
}
128+
return nil
129+
}
130+
68131
func (b *Block) New() header.Header {
69132
return new(Block)
70133
}

types/header.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package types
22

33
import (
44
"encoding"
5+
"errors"
56
"fmt"
67
"time"
78

@@ -145,6 +146,15 @@ func verifyNewHeaderAndVals(trusted, untrusted *Header) error {
145146
return nil
146147
}
147148

149+
// ValidateBasic performs basic validation of a header.
150+
func (h *Header) ValidateBasic() error {
151+
if len(h.ProposerAddress) == 0 {
152+
return errors.New("no proposer address")
153+
}
154+
155+
return nil
156+
}
157+
148158
var _ header.Header = &Header{}
149159
var _ encoding.BinaryMarshaler = &Header{}
150160
var _ encoding.BinaryUnmarshaler = &Header{}

0 commit comments

Comments
 (0)