@@ -42,26 +42,41 @@ func buildSyncTestSigner(tb testing.TB) (addr []byte, pub crypto.PubKey, signer
42
42
return a , p , n
43
43
}
44
44
45
- func makeSignedHeader (t * testing.T , chainID string , height uint64 , proposer []byte , pub crypto.PubKey , signer signerpkg.Signer , appHash []byte ) * types.SignedHeader {
45
+ // makeSignedHeaderBytes builds a valid SignedHeader and returns its binary encoding and the object
46
+ func makeSignedHeaderBytes (tb testing.TB , chainID string , height uint64 , proposer []byte , pub crypto.PubKey , signer signerpkg.Signer , appHash []byte , data * types.Data ) ([]byte , * types.SignedHeader ) {
47
+ time := uint64 (time .Now ().UnixNano ())
48
+ dataHash := common .DataHashForEmptyTxs
49
+ if data != nil {
50
+ time = uint64 (data .Time ().UnixNano ())
51
+ dataHash = data .DACommitment ()
52
+ }
53
+
46
54
hdr := & types.SignedHeader {
47
55
Header : types.Header {
48
- BaseHeader : types.BaseHeader {ChainID : chainID , Height : height , Time : uint64 ( time . Now (). Add ( time . Duration ( height ) * time . Second ). UnixNano ()) },
56
+ BaseHeader : types.BaseHeader {ChainID : chainID , Height : height , Time : time },
49
57
AppHash : appHash ,
58
+ DataHash : dataHash ,
50
59
ProposerAddress : proposer ,
51
60
},
52
61
Signer : types.Signer {PubKey : pub , Address : proposer },
53
62
}
54
- // sign using aggregator provider (sync node will re-verify using sync provider, which defaults to same header bytes)
55
63
bz , err := types .DefaultAggregatorNodeSignatureBytesProvider (& hdr .Header )
56
- require .NoError (t , err )
64
+ require .NoError (tb , err )
57
65
sig , err := signer .Sign (bz )
58
- require .NoError (t , err )
66
+ require .NoError (tb , err )
59
67
hdr .Signature = sig
60
- return hdr
68
+ bin , err := hdr .MarshalBinary ()
69
+ require .NoError (tb , err )
70
+ return bin , hdr
61
71
}
62
72
63
73
func makeData (chainID string , height uint64 , txs int ) * types.Data {
64
- d := & types.Data {Metadata : & types.Metadata {ChainID : chainID , Height : height , Time : uint64 (time .Now ().UnixNano ())}}
74
+ d := & types.Data {
75
+ Metadata : & types.Metadata {
76
+ ChainID : chainID ,
77
+ Height : height ,
78
+ Time : uint64 (time .Now ().Add (time .Duration (height ) * time .Second ).UnixNano ())},
79
+ }
65
80
if txs > 0 {
66
81
d .Txs = make (types.Txs , txs )
67
82
for i := 0 ; i < txs ; i ++ {
@@ -71,6 +86,54 @@ func makeData(chainID string, height uint64, txs int) *types.Data {
71
86
return d
72
87
}
73
88
89
+ func TestSyncer_validateBlock_DataHashMismatch (t * testing.T ) {
90
+ ds := dssync .MutexWrap (datastore .NewMapDatastore ())
91
+ st := store .New (ds )
92
+ cm , err := cache .NewManager (config .DefaultConfig (), st , zerolog .Nop ())
93
+ require .NoError (t , err )
94
+
95
+ addr , pub , signer := buildSyncTestSigner (t )
96
+
97
+ cfg := config .DefaultConfig ()
98
+ gen := genesis.Genesis {ChainID : "tchain" , InitialHeight : 1 , StartTime : time .Now ().Add (- time .Second ), ProposerAddress : addr }
99
+
100
+ mockExec := testmocks .NewMockExecutor (t )
101
+
102
+ s := NewSyncer (
103
+ st ,
104
+ mockExec ,
105
+ nil ,
106
+ cm ,
107
+ common .NopMetrics (),
108
+ cfg ,
109
+ gen ,
110
+ nil ,
111
+ nil ,
112
+ zerolog .Nop (),
113
+ common .DefaultBlockOptions (),
114
+ make (chan error , 1 ),
115
+ )
116
+
117
+ // Create header and data with correct hash
118
+ data := makeData (gen .ChainID , 1 , 2 ) // non-empty
119
+ _ , header := makeSignedHeaderBytes (t , gen .ChainID , 1 , addr , pub , signer , nil , data )
120
+
121
+ err = s .validateBlock (header , data )
122
+ require .NoError (t , err )
123
+
124
+ // Create header and data with mismatched hash
125
+ data = makeData (gen .ChainID , 1 , 2 ) // non-empty
126
+ _ , header = makeSignedHeaderBytes (t , gen .ChainID , 1 , addr , pub , signer , nil , nil )
127
+ err = s .validateBlock (header , data )
128
+ require .Error (t , err )
129
+
130
+ // Create header and empty data
131
+ data = makeData (gen .ChainID , 1 , 0 ) // empty
132
+ _ , header = makeSignedHeaderBytes (t , gen .ChainID , 2 , addr , pub , signer , nil , nil )
133
+ err = s .validateBlock (header , data )
134
+ require .Error (t , err )
135
+ }
136
+
74
137
func TestProcessHeightEvent_SyncsAndUpdatesState (t * testing.T ) {
75
138
ds := dssync .MutexWrap (datastore .NewMapDatastore ())
76
139
st := store .New (ds )
@@ -104,9 +167,8 @@ func TestProcessHeightEvent_SyncsAndUpdatesState(t *testing.T) {
104
167
s .ctx = context .Background ()
105
168
// Create signed header & data for height 1
106
169
lastState := s .GetLastState ()
107
- hdr := makeSignedHeader (t , gen .ChainID , 1 , addr , pub , signer , lastState .AppHash )
108
170
data := makeData (gen .ChainID , 1 , 0 )
109
- // For empty data, header.DataHash should be set by producer; here we don't rely on it for syncing
171
+ _ , hdr := makeSignedHeaderBytes ( t , gen . ChainID , 1 , addr , pub , signer , lastState . AppHash , data )
110
172
111
173
// Expect ExecuteTxs call for height 1
112
174
mockExec .EXPECT ().ExecuteTxs (mock .Anything , mock .Anything , uint64 (1 ), mock .Anything , lastState .AppHash ).
@@ -154,17 +216,17 @@ func TestSequentialBlockSync(t *testing.T) {
154
216
155
217
// Sync two consecutive blocks via processHeightEvent so ExecuteTxs is called and state stored
156
218
st0 := s .GetLastState ()
157
- hdr1 := makeSignedHeader (t , gen .ChainID , 1 , addr , pub , signer , st0 .AppHash )
158
219
data1 := makeData (gen .ChainID , 1 , 1 ) // non-empty
220
+ _ , hdr1 := makeSignedHeaderBytes (t , gen .ChainID , 1 , addr , pub , signer , st0 .AppHash , data1 )
159
221
// Expect ExecuteTxs call for height 1
160
222
mockExec .EXPECT ().ExecuteTxs (mock .Anything , mock .Anything , uint64 (1 ), mock .Anything , st0 .AppHash ).
161
223
Return ([]byte ("app1" ), uint64 (1024 ), nil ).Once ()
162
224
evt1 := common.DAHeightEvent {Header : hdr1 , Data : data1 , DaHeight : 10 }
163
225
s .processHeightEvent (& evt1 )
164
226
165
227
st1 , _ := st .GetState (context .Background ())
166
- hdr2 := makeSignedHeader (t , gen .ChainID , 2 , addr , pub , signer , st1 .AppHash )
167
228
data2 := makeData (gen .ChainID , 2 , 0 ) // empty data
229
+ _ , hdr2 := makeSignedHeaderBytes (t , gen .ChainID , 2 , addr , pub , signer , st1 .AppHash , data2 )
168
230
// Expect ExecuteTxs call for height 2
169
231
mockExec .EXPECT ().ExecuteTxs (mock .Anything , mock .Anything , uint64 (2 ), mock .Anything , st1 .AppHash ).
170
232
Return ([]byte ("app2" ), uint64 (1024 ), nil ).Once ()
@@ -287,17 +349,17 @@ func TestSyncLoopPersistState(t *testing.T) {
287
349
// with n da blobs fetched
288
350
for i := range myFutureDAHeight - myDAHeightOffset {
289
351
chainHeight , daHeight := i , i + myDAHeightOffset
290
- _ , sigHeader := makeSignedHeaderBytes (t , gen .ChainID , chainHeight , addr , pub , signer , nil , nil )
291
- emptyData := types.Data {
352
+ emptyData := & types.Data {
292
353
Metadata : & types.Metadata {
293
- ChainID : sigHeader .ChainID () ,
294
- Height : sigHeader . Height () ,
295
- Time : sigHeader . BaseHeader . Time ,
354
+ ChainID : gen .ChainID ,
355
+ Height : chainHeight ,
356
+ Time : uint64 ( time . Now (). Add ( time . Duration ( chainHeight ) * time . Second ). UnixNano ()) ,
296
357
},
297
358
}
359
+ _ , sigHeader := makeSignedHeaderBytes (t , gen .ChainID , chainHeight , addr , pub , signer , nil , emptyData )
298
360
evts := []common.DAHeightEvent {{
299
361
Header : sigHeader ,
300
- Data : & emptyData ,
362
+ Data : emptyData ,
301
363
DaHeight : daHeight ,
302
364
}}
303
365
daRtrMock .On ("RetrieveFromDA" , mock .Anything , daHeight ).Return (evts , nil )
0 commit comments