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  }