github.com/onflow/flow-go@v0.33.17/model/convert/service_event_test.go (about) 1 package convert_test 2 3 import ( 4 "fmt" 5 "testing" 6 7 "github.com/onflow/cadence" 8 "github.com/onflow/cadence/encoding/ccf" 9 "github.com/stretchr/testify/assert" 10 "github.com/stretchr/testify/require" 11 12 "github.com/onflow/flow-go/fvm/systemcontracts" 13 "github.com/onflow/flow-go/model/convert" 14 "github.com/onflow/flow-go/model/flow" 15 "github.com/onflow/flow-go/utils/unittest" 16 ) 17 18 func TestEventConversion(t *testing.T) { 19 20 chainID := flow.Emulator 21 22 t.Run( 23 "epoch setup", func(t *testing.T) { 24 25 fixture, expected := unittest.EpochSetupFixtureByChainID(chainID) 26 27 // convert Cadence types to Go types 28 event, err := convert.ServiceEvent(chainID, fixture) 29 require.NoError(t, err) 30 require.NotNil(t, event) 31 32 // cast event type to epoch setup 33 actual, ok := event.Event.(*flow.EpochSetup) 34 require.True(t, ok) 35 36 assert.Equal(t, expected, actual) 37 38 }, 39 ) 40 41 t.Run( 42 "epoch setup with random source with leading zeroes", func(t *testing.T) { 43 44 fixture, _ := unittest.EpochSetupFixtureByChainID(chainID) 45 // all zero source to cover all cases of endiannesses 46 randomSource := make([]byte, flow.EpochSetupRandomSourceLength) 47 // update the random source in event fixture 48 fixture.Payload = unittest.EpochSetupFixtureCCF(randomSource) 49 50 // convert Cadence types to Go types 51 event, err := convert.ServiceEvent(chainID, fixture) 52 require.NoError(t, err) 53 require.NotNil(t, event) 54 55 // cast event type to epoch setup 56 _, ok := event.Event.(*flow.EpochSetup) 57 require.True(t, ok) 58 }, 59 ) 60 61 t.Run( 62 "epoch setup with short random source", func(t *testing.T) { 63 64 fixture, _ := unittest.EpochSetupFixtureByChainID(chainID) 65 // update the random source in event fixture 66 randomSource := unittest.EpochSetupRandomSourceFixture() 67 fixture.Payload = unittest.EpochSetupFixtureCCF(randomSource[:flow.EpochSetupRandomSourceLength-1]) 68 69 // convert Cadence types to Go types 70 event, err := convert.ServiceEvent(chainID, fixture) 71 require.Error(t, err) 72 require.Nil(t, event) 73 }, 74 ) 75 76 t.Run( 77 "epoch setup with non-hex random source", func(t *testing.T) { 78 79 fixture, _ := unittest.EpochSetupFixtureByChainID(chainID) 80 // update the random source in event fixture 81 fixture.Payload = unittest.EpochSetupCCFWithNonHexRandomSource() 82 83 // convert Cadence types to Go types 84 event, err := convert.ServiceEvent(chainID, fixture) 85 require.Error(t, err) 86 require.Nil(t, event) 87 }, 88 ) 89 90 t.Run( 91 "epoch commit", func(t *testing.T) { 92 93 fixture, expected := unittest.EpochCommitFixtureByChainID(chainID) 94 95 // convert Cadence types to Go types 96 event, err := convert.ServiceEvent(chainID, fixture) 97 require.NoError(t, err) 98 require.NotNil(t, event) 99 100 // cast event type to epoch commit 101 actual, ok := event.Event.(*flow.EpochCommit) 102 require.True(t, ok) 103 104 assert.Equal(t, expected, actual) 105 }, 106 ) 107 108 t.Run( 109 "version beacon", func(t *testing.T) { 110 111 fixture, expected := unittest.VersionBeaconFixtureByChainID(chainID) 112 113 // convert Cadence types to Go types 114 event, err := convert.ServiceEvent(chainID, fixture) 115 require.NoError(t, err) 116 require.NotNil(t, event) 117 118 // cast event type to version beacon 119 actual, ok := event.Event.(*flow.VersionBeacon) 120 require.True(t, ok) 121 122 assert.Equal(t, expected, actual) 123 }, 124 ) 125 } 126 127 func TestDecodeCadenceValue(t *testing.T) { 128 129 tests := []struct { 130 name string 131 location string 132 value cadence.Value 133 decodeInner func(cadence.Value) (interface{}, error) 134 expected interface{} 135 expectError bool 136 expectedLocation string 137 }{ 138 { 139 name: "Basic", 140 location: "test", 141 value: cadence.UInt64(42), 142 decodeInner: func(value cadence.Value) ( 143 interface{}, 144 error, 145 ) { 146 return 42, nil 147 }, 148 expected: 42, 149 expectError: false, 150 }, 151 { 152 name: "Nil value", 153 location: "test", 154 value: nil, 155 decodeInner: func(value cadence.Value) ( 156 interface{}, 157 error, 158 ) { 159 return 42, nil 160 }, 161 expected: nil, 162 expectError: true, 163 }, 164 { 165 name: "Custom decode error", 166 location: "test", 167 value: cadence.String("hello"), 168 decodeInner: func(value cadence.Value) ( 169 interface{}, 170 error, 171 ) { 172 return nil, fmt.Errorf("custom error") 173 }, 174 expected: nil, 175 expectError: true, 176 }, 177 { 178 name: "Nested location", 179 location: "outer", 180 value: cadence.String("hello"), 181 decodeInner: func(value cadence.Value) (interface{}, error) { 182 return convert.DecodeCadenceValue( 183 ".inner", value, 184 func(value cadence.Value) (interface{}, error) { 185 return nil, fmt.Errorf("custom error") 186 }, 187 ) 188 }, 189 expected: nil, 190 expectError: true, 191 expectedLocation: "outer.inner", 192 }, 193 } 194 195 for _, tt := range tests { 196 t.Run( 197 tt.name, func(t *testing.T) { 198 result, err := convert.DecodeCadenceValue( 199 tt.location, 200 tt.value, 201 tt.decodeInner, 202 ) 203 204 if tt.expectError { 205 assert.Error(t, err) 206 if tt.expectedLocation != "" { 207 assert.Contains(t, err.Error(), tt.expectedLocation) 208 } 209 } else { 210 assert.NoError(t, err) 211 assert.Equal(t, tt.expected, result) 212 } 213 }, 214 ) 215 } 216 } 217 218 func TestVersionBeaconEventConversion(t *testing.T) { 219 versionBoundaryType := unittest.NewNodeVersionBeaconVersionBoundaryStructType() 220 semverType := unittest.NewNodeVersionBeaconSemverStructType() 221 eventType := unittest.NewNodeVersionBeaconVersionBeaconEventType() 222 223 type vbTestCase struct { 224 name string 225 event cadence.Event 226 converted *flow.VersionBeacon 227 expectAndHandleError func(t *testing.T, err error) 228 } 229 230 runVersionBeaconTestCase := func(t *testing.T, test vbTestCase) { 231 chainID := flow.Emulator 232 t.Run(test.name, func(t *testing.T) { 233 events := systemcontracts.ServiceEventsForChain(chainID) 234 235 var err error 236 event := unittest.EventFixture(events.VersionBeacon.EventType(), 1, 1, unittest.IdentifierFixture(), 0) 237 event.Payload, err = ccf.Encode(test.event) 238 require.NoError(t, err) 239 240 // convert Cadence types to Go types 241 serviceEvent, err := convert.ServiceEvent(chainID, event) 242 243 if test.expectAndHandleError != nil { 244 require.Error(t, err) 245 test.expectAndHandleError(t, err) 246 return 247 } 248 249 require.NoError(t, err) 250 require.NotNil(t, event) 251 252 // cast event type to version beacon 253 actual, ok := serviceEvent.Event.(*flow.VersionBeacon) 254 require.True(t, ok) 255 256 require.Equal(t, test.converted, actual) 257 }) 258 } 259 260 runVersionBeaconTestCase(t, 261 vbTestCase{ 262 name: "with pre-release", 263 event: cadence.NewEvent( 264 []cadence.Value{ 265 // versionBoundaries 266 cadence.NewArray( 267 []cadence.Value{ 268 cadence.NewStruct( 269 []cadence.Value{ 270 // blockHeight 271 cadence.UInt64(44), 272 // version 273 cadence.NewStruct( 274 []cadence.Value{ 275 // major 276 cadence.UInt8(2), 277 // minor 278 cadence.UInt8(13), 279 // patch 280 cadence.UInt8(7), 281 // preRelease 282 cadence.NewOptional(cadence.String("test")), 283 }, 284 ).WithType(semverType), 285 }, 286 ).WithType(versionBoundaryType), 287 }, 288 ).WithType(cadence.NewVariableSizedArrayType(versionBoundaryType)), 289 // sequence 290 cadence.UInt64(5), 291 }, 292 ).WithType(eventType), 293 converted: &flow.VersionBeacon{ 294 VersionBoundaries: []flow.VersionBoundary{ 295 { 296 BlockHeight: 44, 297 Version: "2.13.7-test", 298 }, 299 }, 300 Sequence: 5, 301 }, 302 }, 303 ) 304 305 runVersionBeaconTestCase(t, 306 vbTestCase{ 307 name: "without pre-release", 308 event: cadence.NewEvent( 309 []cadence.Value{ 310 // versionBoundaries 311 cadence.NewArray( 312 []cadence.Value{ 313 cadence.NewStruct( 314 []cadence.Value{ 315 // blockHeight 316 cadence.UInt64(44), 317 // version 318 cadence.NewStruct( 319 []cadence.Value{ 320 // major 321 cadence.UInt8(2), 322 // minor 323 cadence.UInt8(13), 324 // patch 325 cadence.UInt8(7), 326 // preRelease 327 cadence.NewOptional(nil), 328 }, 329 ).WithType(semverType), 330 }, 331 ).WithType(versionBoundaryType), 332 }, 333 ).WithType(cadence.NewVariableSizedArrayType(versionBoundaryType)), 334 // sequence 335 cadence.UInt64(5), 336 }, 337 ).WithType(eventType), 338 converted: &flow.VersionBeacon{ 339 VersionBoundaries: []flow.VersionBoundary{ 340 { 341 BlockHeight: 44, 342 Version: "2.13.7", 343 }, 344 }, 345 Sequence: 5, 346 }, 347 }, 348 ) 349 runVersionBeaconTestCase(t, 350 vbTestCase{ 351 name: "invalid pre-release", 352 event: cadence.NewEvent( 353 []cadence.Value{ 354 // versionBoundaries 355 cadence.NewArray( 356 []cadence.Value{ 357 cadence.NewStruct( 358 []cadence.Value{ 359 // blockHeight 360 cadence.UInt64(44), 361 // version 362 cadence.NewStruct( 363 []cadence.Value{ 364 // major 365 cadence.UInt8(2), 366 // minor 367 cadence.UInt8(13), 368 // patch 369 cadence.UInt8(7), 370 // preRelease 371 cadence.NewOptional(cadence.String("/slashes.not.allowed")), 372 }, 373 ).WithType(semverType), 374 }, 375 ).WithType(versionBoundaryType), 376 }, 377 ).WithType(cadence.NewVariableSizedArrayType(versionBoundaryType)), 378 // sequence 379 cadence.UInt64(5), 380 }, 381 ).WithType(eventType), 382 expectAndHandleError: func(t *testing.T, err error) { 383 require.ErrorContains(t, err, "failed to validate pre-release") 384 }, 385 }, 386 ) 387 }