github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/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 t.Run("protocol state version upgrade", func(t *testing.T) { 127 fixture, expected := unittest.ProtocolStateVersionUpgradeFixtureByChainID(chainID) 128 129 // convert Cadence types to Go types 130 event, err := convert.ServiceEvent(chainID, fixture) 131 require.NoError(t, err) 132 require.NotNil(t, event) 133 134 // cast event type to version upgrade 135 actual, ok := event.Event.(*flow.ProtocolStateVersionUpgrade) 136 require.True(t, ok) 137 138 assert.Equal(t, expected, actual) 139 }) 140 } 141 142 func TestDecodeCadenceValue(t *testing.T) { 143 144 tests := []struct { 145 name string 146 location string 147 value cadence.Value 148 decodeInner func(cadence.Value) (interface{}, error) 149 expected interface{} 150 expectError bool 151 expectedLocation string 152 }{ 153 { 154 name: "Basic", 155 location: "test", 156 value: cadence.UInt64(42), 157 decodeInner: func(value cadence.Value) ( 158 interface{}, 159 error, 160 ) { 161 return 42, nil 162 }, 163 expected: 42, 164 expectError: false, 165 }, 166 { 167 name: "Nil value", 168 location: "test", 169 value: nil, 170 decodeInner: func(value cadence.Value) ( 171 interface{}, 172 error, 173 ) { 174 return 42, nil 175 }, 176 expected: nil, 177 expectError: true, 178 }, 179 { 180 name: "Custom decode error", 181 location: "test", 182 value: cadence.String("hello"), 183 decodeInner: func(value cadence.Value) ( 184 interface{}, 185 error, 186 ) { 187 return nil, fmt.Errorf("custom error") 188 }, 189 expected: nil, 190 expectError: true, 191 }, 192 { 193 name: "Nested location", 194 location: "outer", 195 value: cadence.String("hello"), 196 decodeInner: func(value cadence.Value) (interface{}, error) { 197 return convert.DecodeCadenceValue( 198 ".inner", value, 199 func(value cadence.Value) (interface{}, error) { 200 return nil, fmt.Errorf("custom error") 201 }, 202 ) 203 }, 204 expected: nil, 205 expectError: true, 206 expectedLocation: "outer.inner", 207 }, 208 } 209 210 for _, tt := range tests { 211 t.Run( 212 tt.name, func(t *testing.T) { 213 result, err := convert.DecodeCadenceValue( 214 tt.location, 215 tt.value, 216 tt.decodeInner, 217 ) 218 219 if tt.expectError { 220 assert.Error(t, err) 221 if tt.expectedLocation != "" { 222 assert.Contains(t, err.Error(), tt.expectedLocation) 223 } 224 } else { 225 assert.NoError(t, err) 226 assert.Equal(t, tt.expected, result) 227 } 228 }, 229 ) 230 } 231 } 232 233 func TestVersionBeaconEventConversion(t *testing.T) { 234 versionBoundaryType := unittest.NewNodeVersionBeaconVersionBoundaryStructType() 235 semverType := unittest.NewNodeVersionBeaconSemverStructType() 236 eventType := unittest.NewNodeVersionBeaconVersionBeaconEventType() 237 238 type vbTestCase struct { 239 name string 240 event cadence.Event 241 converted *flow.VersionBeacon 242 expectAndHandleError func(t *testing.T, err error) 243 } 244 245 runVersionBeaconTestCase := func(t *testing.T, test vbTestCase) { 246 chainID := flow.Emulator 247 t.Run(test.name, func(t *testing.T) { 248 events := systemcontracts.ServiceEventsForChain(chainID) 249 250 var err error 251 event := unittest.EventFixture(events.VersionBeacon.EventType(), 1, 1, unittest.IdentifierFixture(), 0) 252 event.Payload, err = ccf.Encode(test.event) 253 require.NoError(t, err) 254 255 // convert Cadence types to Go types 256 serviceEvent, err := convert.ServiceEvent(chainID, event) 257 258 if test.expectAndHandleError != nil { 259 require.Error(t, err) 260 test.expectAndHandleError(t, err) 261 return 262 } 263 264 require.NoError(t, err) 265 require.NotNil(t, event) 266 267 // cast event type to version beacon 268 actual, ok := serviceEvent.Event.(*flow.VersionBeacon) 269 require.True(t, ok) 270 271 require.Equal(t, test.converted, actual) 272 }) 273 } 274 275 runVersionBeaconTestCase(t, 276 vbTestCase{ 277 name: "with pre-release", 278 event: cadence.NewEvent( 279 []cadence.Value{ 280 // versionBoundaries 281 cadence.NewArray( 282 []cadence.Value{ 283 cadence.NewStruct( 284 []cadence.Value{ 285 // blockHeight 286 cadence.UInt64(44), 287 // version 288 cadence.NewStruct( 289 []cadence.Value{ 290 // major 291 cadence.UInt8(2), 292 // minor 293 cadence.UInt8(13), 294 // patch 295 cadence.UInt8(7), 296 // preRelease 297 cadence.NewOptional(cadence.String("test")), 298 }, 299 ).WithType(semverType), 300 }, 301 ).WithType(versionBoundaryType), 302 }, 303 ).WithType(cadence.NewVariableSizedArrayType(versionBoundaryType)), 304 // sequence 305 cadence.UInt64(5), 306 }, 307 ).WithType(eventType), 308 converted: &flow.VersionBeacon{ 309 VersionBoundaries: []flow.VersionBoundary{ 310 { 311 BlockHeight: 44, 312 Version: "2.13.7-test", 313 }, 314 }, 315 Sequence: 5, 316 }, 317 }, 318 ) 319 320 runVersionBeaconTestCase(t, 321 vbTestCase{ 322 name: "without pre-release", 323 event: cadence.NewEvent( 324 []cadence.Value{ 325 // versionBoundaries 326 cadence.NewArray( 327 []cadence.Value{ 328 cadence.NewStruct( 329 []cadence.Value{ 330 // blockHeight 331 cadence.UInt64(44), 332 // version 333 cadence.NewStruct( 334 []cadence.Value{ 335 // major 336 cadence.UInt8(2), 337 // minor 338 cadence.UInt8(13), 339 // patch 340 cadence.UInt8(7), 341 // preRelease 342 cadence.NewOptional(nil), 343 }, 344 ).WithType(semverType), 345 }, 346 ).WithType(versionBoundaryType), 347 }, 348 ).WithType(cadence.NewVariableSizedArrayType(versionBoundaryType)), 349 // sequence 350 cadence.UInt64(5), 351 }, 352 ).WithType(eventType), 353 converted: &flow.VersionBeacon{ 354 VersionBoundaries: []flow.VersionBoundary{ 355 { 356 BlockHeight: 44, 357 Version: "2.13.7", 358 }, 359 }, 360 Sequence: 5, 361 }, 362 }, 363 ) 364 runVersionBeaconTestCase(t, 365 vbTestCase{ 366 name: "invalid pre-release", 367 event: cadence.NewEvent( 368 []cadence.Value{ 369 // versionBoundaries 370 cadence.NewArray( 371 []cadence.Value{ 372 cadence.NewStruct( 373 []cadence.Value{ 374 // blockHeight 375 cadence.UInt64(44), 376 // version 377 cadence.NewStruct( 378 []cadence.Value{ 379 // major 380 cadence.UInt8(2), 381 // minor 382 cadence.UInt8(13), 383 // patch 384 cadence.UInt8(7), 385 // preRelease 386 cadence.NewOptional(cadence.String("/slashes.not.allowed")), 387 }, 388 ).WithType(semverType), 389 }, 390 ).WithType(versionBoundaryType), 391 }, 392 ).WithType(cadence.NewVariableSizedArrayType(versionBoundaryType)), 393 // sequence 394 cadence.UInt64(5), 395 }, 396 ).WithType(eventType), 397 expectAndHandleError: func(t *testing.T, err error) { 398 require.ErrorContains(t, err, "failed to validate pre-release") 399 }, 400 }, 401 ) 402 }