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  }