github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/engine/common/rpc/convert/execution_data_test.go (about)

     1  package convert_test
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/stretchr/testify/assert"
     7  	"github.com/stretchr/testify/require"
     8  
     9  	"github.com/onflow/cadence/encoding/ccf"
    10  	jsoncdc "github.com/onflow/cadence/encoding/json"
    11  	"github.com/onflow/flow/protobuf/go/flow/entities"
    12  
    13  	"github.com/onflow/flow-go/engine/common/rpc/convert"
    14  	"github.com/onflow/flow-go/ledger/common/testutils"
    15  	"github.com/onflow/flow-go/model/flow"
    16  	"github.com/onflow/flow-go/module/executiondatasync/execution_data"
    17  	"github.com/onflow/flow-go/utils/unittest"
    18  	"github.com/onflow/flow-go/utils/unittest/generator"
    19  )
    20  
    21  func TestConvertBlockExecutionDataEventPayloads(t *testing.T) {
    22  	// generators will produce identical event payloads (before encoding)
    23  	ccfEvents := generator.GetEventsWithEncoding(3, entities.EventEncodingVersion_CCF_V0)
    24  	jsonEvents := make([]flow.Event, len(ccfEvents))
    25  	for i, e := range ccfEvents {
    26  		jsonEvent, err := convert.CcfEventToJsonEvent(e)
    27  		require.NoError(t, err)
    28  		jsonEvents[i] = *jsonEvent
    29  	}
    30  
    31  	// generate BlockExecutionData with CCF encoded events
    32  	executionData := unittest.BlockExecutionDataFixture(
    33  		unittest.WithChunkExecutionDatas(
    34  			unittest.ChunkExecutionDataFixture(t, 1024, unittest.WithChunkEvents(ccfEvents)),
    35  			unittest.ChunkExecutionDataFixture(t, 1024, unittest.WithChunkEvents(ccfEvents)),
    36  		),
    37  	)
    38  
    39  	execDataMessage, err := convert.BlockExecutionDataToMessage(executionData)
    40  	require.NoError(t, err)
    41  
    42  	t.Run("regular convert does not modify payload encoding", func(t *testing.T) {
    43  		for _, chunk := range execDataMessage.GetChunkExecutionData() {
    44  			events := convert.MessagesToEvents(chunk.Events)
    45  			for i, e := range events {
    46  				assert.Equal(t, ccfEvents[i], e)
    47  
    48  				_, err := ccf.Decode(nil, e.Payload)
    49  				require.NoError(t, err)
    50  			}
    51  		}
    52  	})
    53  
    54  	t.Run("converted event payloads are encoded in jsoncdc", func(t *testing.T) {
    55  		err = convert.BlockExecutionDataEventPayloadsToVersion(execDataMessage, entities.EventEncodingVersion_JSON_CDC_V0)
    56  		require.NoError(t, err)
    57  
    58  		for _, chunk := range execDataMessage.GetChunkExecutionData() {
    59  			events := convert.MessagesToEvents(chunk.Events)
    60  			for i, e := range events {
    61  				assert.Equal(t, jsonEvents[i], e)
    62  
    63  				_, err := jsoncdc.Decode(nil, e.Payload)
    64  				require.NoError(t, err)
    65  			}
    66  		}
    67  	})
    68  }
    69  
    70  func TestConvertBlockExecutionData(t *testing.T) {
    71  	t.Parallel()
    72  
    73  	chain := flow.Testnet.Chain() // this is used by the AddressFixture
    74  	events := unittest.EventsFixture(5)
    75  
    76  	chunks := 5
    77  	chunkData := make([]*execution_data.ChunkExecutionData, 0, chunks)
    78  	for i := 0; i < chunks-1; i++ {
    79  		ced := unittest.ChunkExecutionDataFixture(t,
    80  			0, // updates set explicitly to target 160-320KB per chunk
    81  			unittest.WithChunkEvents(events),
    82  			unittest.WithTrieUpdate(testutils.TrieUpdateFixture(5, 32*1024, 64*1024)),
    83  		)
    84  
    85  		chunkData = append(chunkData, ced)
    86  	}
    87  	makeServiceTx := func(ced *execution_data.ChunkExecutionData) {
    88  		// proposal key and payer are empty addresses for service tx
    89  		collection := unittest.CollectionFixture(1)
    90  		collection.Transactions[0].ProposalKey.Address = flow.EmptyAddress
    91  		collection.Transactions[0].Payer = flow.EmptyAddress
    92  		ced.Collection = &collection
    93  
    94  		// the service chunk sometimes does not have any trie updates
    95  		ced.TrieUpdate = nil
    96  	}
    97  	chunk := unittest.ChunkExecutionDataFixture(t, execution_data.DefaultMaxBlobSize/5, unittest.WithChunkEvents(events), makeServiceTx)
    98  	chunkData = append(chunkData, chunk)
    99  
   100  	blockData := unittest.BlockExecutionDataFixture(unittest.WithChunkExecutionDatas(chunkData...))
   101  
   102  	msg, err := convert.BlockExecutionDataToMessage(blockData)
   103  	require.NoError(t, err)
   104  
   105  	converted, err := convert.MessageToBlockExecutionData(msg, chain)
   106  	require.NoError(t, err)
   107  
   108  	assert.Equal(t, blockData, converted)
   109  	for i, chunk := range blockData.ChunkExecutionDatas {
   110  		if chunk.TrieUpdate == nil {
   111  			assert.Nil(t, converted.ChunkExecutionDatas[i].TrieUpdate)
   112  		} else {
   113  			assert.True(t, chunk.TrieUpdate.Equals(converted.ChunkExecutionDatas[i].TrieUpdate))
   114  		}
   115  	}
   116  }
   117  
   118  func TestConvertChunkExecutionData(t *testing.T) {
   119  	tests := []struct {
   120  		name string
   121  		fn   func(*testing.T) *execution_data.ChunkExecutionData
   122  	}{
   123  		{
   124  			name: "chunk execution data conversions",
   125  			fn: func(t *testing.T) *execution_data.ChunkExecutionData {
   126  				return unittest.ChunkExecutionDataFixture(t,
   127  					0, // updates set explicitly to target 160-320KB per chunk
   128  					unittest.WithChunkEvents(unittest.EventsFixture(5)),
   129  					unittest.WithTrieUpdate(testutils.TrieUpdateFixture(5, 32*1024, 64*1024)),
   130  				)
   131  			},
   132  		},
   133  		{
   134  			name: "chunk execution data conversions - no events",
   135  			fn: func(t *testing.T) *execution_data.ChunkExecutionData {
   136  				ced := unittest.ChunkExecutionDataFixture(t, 0)
   137  				ced.Events = nil
   138  				return ced
   139  			},
   140  		},
   141  		{
   142  			name: "chunk execution data conversions - no trie update",
   143  			fn: func(t *testing.T) *execution_data.ChunkExecutionData {
   144  				ced := unittest.ChunkExecutionDataFixture(t, 0)
   145  				ced.TrieUpdate = nil
   146  				return ced
   147  			},
   148  		},
   149  		{
   150  			name: "chunk execution data conversions - empty collection",
   151  			fn: func(t *testing.T) *execution_data.ChunkExecutionData {
   152  				ced := unittest.ChunkExecutionDataFixture(t, 0)
   153  				ced.Collection = &flow.Collection{}
   154  				ced.TransactionResults = nil
   155  				return ced
   156  			},
   157  		},
   158  	}
   159  
   160  	for _, test := range tests {
   161  		t.Run(test.name, func(t *testing.T) {
   162  			ced := test.fn(t)
   163  
   164  			chunkMsg, err := convert.ChunkExecutionDataToMessage(ced)
   165  			require.NoError(t, err)
   166  
   167  			chunkReConverted, err := convert.MessageToChunkExecutionData(chunkMsg, flow.Testnet.Chain())
   168  			require.NoError(t, err)
   169  
   170  			assert.Equal(t, ced, chunkReConverted)
   171  			if ced.TrieUpdate == nil {
   172  				assert.Nil(t, chunkReConverted.TrieUpdate)
   173  			} else {
   174  				assert.True(t, ced.TrieUpdate.Equals(chunkReConverted.TrieUpdate))
   175  			}
   176  		})
   177  	}
   178  }
   179  
   180  func TestMessageToRegisterID(t *testing.T) {
   181  	chain := flow.Testnet.Chain()
   182  	tests := []struct {
   183  		name  string
   184  		regID flow.RegisterID
   185  	}{
   186  		{
   187  			name:  "service level register id",
   188  			regID: flow.UUIDRegisterID(0),
   189  		},
   190  		{
   191  			name:  "account level register id",
   192  			regID: flow.AccountStatusRegisterID(unittest.AddressFixture()),
   193  		},
   194  		{
   195  			name:  "regular register id",
   196  			regID: unittest.RegisterIDFixture(),
   197  		},
   198  	}
   199  
   200  	for _, test := range tests {
   201  		t.Run(test.name, func(t *testing.T) {
   202  			msg := convert.RegisterIDToMessage(test.regID)
   203  			converted, err := convert.MessageToRegisterID(msg, chain)
   204  			require.NoError(t, err)
   205  			assert.Equal(t, test.regID, converted)
   206  		})
   207  	}
   208  
   209  	t.Run("nil owner converts to empty string", func(t *testing.T) {
   210  		msg := &entities.RegisterID{
   211  			Owner: nil,
   212  			Key:   []byte("key"),
   213  		}
   214  		converted, err := convert.MessageToRegisterID(msg, chain)
   215  		require.NoError(t, err)
   216  		assert.Equal(t, "", converted.Owner)
   217  		assert.Equal(t, "key", converted.Key)
   218  	})
   219  
   220  	t.Run("nil message returns error", func(t *testing.T) {
   221  		_, err := convert.MessageToRegisterID(nil, chain)
   222  		require.ErrorIs(t, err, convert.ErrEmptyMessage)
   223  	})
   224  
   225  	t.Run("invalid address returns error", func(t *testing.T) {
   226  		// addresses for other chains are invalid
   227  		registerID := flow.NewRegisterID(
   228  			unittest.RandomAddressFixtureForChain(flow.Mainnet),
   229  			"key",
   230  		)
   231  
   232  		msg := convert.RegisterIDToMessage(registerID)
   233  		_, err := convert.MessageToRegisterID(msg, chain)
   234  		require.Error(t, err)
   235  	})
   236  
   237  	t.Run("multiple registerIDs", func(t *testing.T) {
   238  		expected := flow.RegisterIDs{
   239  			flow.UUIDRegisterID(0),
   240  			flow.AccountStatusRegisterID(unittest.AddressFixture()),
   241  			unittest.RegisterIDFixture(),
   242  		}
   243  
   244  		messages := make([]*entities.RegisterID, len(expected))
   245  		for i, regID := range expected {
   246  			regID := regID
   247  			messages[i] = convert.RegisterIDToMessage(regID)
   248  			require.Equal(t, regID.Owner, string(messages[i].Owner))
   249  			require.Equal(t, regID.Key, string(messages[i].Key))
   250  		}
   251  
   252  		actual, err := convert.MessagesToRegisterIDs(messages, chain)
   253  		require.NoError(t, err)
   254  		assert.Equal(t, expected, actual)
   255  	})
   256  }