github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/state/protocol/inmem/convert_test.go (about)

     1  package inmem_test
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"testing"
     7  
     8  	"github.com/dgraph-io/badger/v2"
     9  	"github.com/stretchr/testify/assert"
    10  	"github.com/stretchr/testify/require"
    11  
    12  	"github.com/onflow/flow-go/model/flow"
    13  	"github.com/onflow/flow-go/state/protocol"
    14  	bprotocol "github.com/onflow/flow-go/state/protocol/badger"
    15  	"github.com/onflow/flow-go/state/protocol/inmem"
    16  	"github.com/onflow/flow-go/state/protocol/util"
    17  	"github.com/onflow/flow-go/utils/unittest"
    18  )
    19  
    20  // TestFromSnapshot tests that we are able to convert a database-backed snapshot
    21  // to a memory-backed snapshot.
    22  func TestFromSnapshot(t *testing.T) {
    23  	identities := unittest.IdentityListFixture(10, unittest.WithAllRoles())
    24  	rootSnapshot := unittest.RootSnapshotFixture(identities)
    25  
    26  	util.RunWithFullProtocolStateAndMutator(t, rootSnapshot, func(db *badger.DB, fullState *bprotocol.ParticipantState, mutableState protocol.MutableProtocolState) {
    27  		state := fullState.FollowerState
    28  		epochBuilder := unittest.NewEpochBuilder(t, mutableState, state)
    29  		// build epoch 1 (prepare epoch 2)
    30  		epochBuilder.
    31  			BuildEpoch().
    32  			CompleteEpoch()
    33  		// build epoch 2 (prepare epoch 3)
    34  		epochBuilder.
    35  			BuildEpoch().
    36  			CompleteEpoch()
    37  
    38  		// get heights of each phase in built epochs
    39  		epoch1, ok := epochBuilder.EpochHeights(1)
    40  		require.True(t, ok)
    41  		epoch2, ok := epochBuilder.EpochHeights(2)
    42  		require.True(t, ok)
    43  
    44  		// test that we are able to retrieve an in-memory version of root snapshot
    45  		t.Run("root snapshot", func(t *testing.T) {
    46  			root := state.Params().FinalizedRoot()
    47  			expected := state.AtHeight(root.Height)
    48  			actual, err := inmem.FromSnapshot(expected)
    49  			require.NoError(t, err)
    50  			assertSnapshotsEqual(t, expected, actual)
    51  			testEncodeDecode(t, actual)
    52  		})
    53  
    54  		// test getting an in-memory snapshot for all phase of epoch 1
    55  		t.Run("epoch 1", func(t *testing.T) {
    56  			t.Run("staking phase", func(t *testing.T) {
    57  				expected := state.AtHeight(epoch1.Staking)
    58  				actual, err := inmem.FromSnapshot(expected)
    59  				require.NoError(t, err)
    60  				assertSnapshotsEqual(t, expected, actual)
    61  				testEncodeDecode(t, actual)
    62  			})
    63  			t.Run("setup phase", func(t *testing.T) {
    64  				expected := state.AtHeight(epoch1.Setup)
    65  				actual, err := inmem.FromSnapshot(expected)
    66  				require.NoError(t, err)
    67  				assertSnapshotsEqual(t, expected, actual)
    68  				testEncodeDecode(t, actual)
    69  			})
    70  			t.Run("committed phase", func(t *testing.T) {
    71  				expected := state.AtHeight(epoch1.Committed)
    72  				actual, err := inmem.FromSnapshot(expected)
    73  				require.NoError(t, err)
    74  				assertSnapshotsEqual(t, expected, actual)
    75  				testEncodeDecode(t, actual)
    76  			})
    77  		})
    78  
    79  		// test getting an in-memory snapshot for all phase of epoch 2
    80  		t.Run("epoch 2", func(t *testing.T) {
    81  			t.Run("staking phase", func(t *testing.T) {
    82  				expected := state.AtHeight(epoch2.Staking)
    83  				actual, err := inmem.FromSnapshot(expected)
    84  				require.NoError(t, err)
    85  				assertSnapshotsEqual(t, expected, actual)
    86  				testEncodeDecode(t, actual)
    87  			})
    88  			t.Run("setup phase", func(t *testing.T) {
    89  				expected := state.AtHeight(epoch2.Setup)
    90  				actual, err := inmem.FromSnapshot(expected)
    91  				require.NoError(t, err)
    92  				assertSnapshotsEqual(t, expected, actual)
    93  				testEncodeDecode(t, actual)
    94  			})
    95  			t.Run("committed phase", func(t *testing.T) {
    96  				expected := state.AtHeight(epoch2.Committed)
    97  				actual, err := inmem.FromSnapshot(expected)
    98  				require.NoError(t, err)
    99  				assertSnapshotsEqual(t, expected, actual)
   100  				testEncodeDecode(t, actual)
   101  			})
   102  		})
   103  
   104  		// ensure last version beacon is included
   105  		t.Run("version beacon", func(t *testing.T) {
   106  			expectedVB := &flow.SealedVersionBeacon{
   107  				VersionBeacon: unittest.VersionBeaconFixture(
   108  					unittest.WithBoundaries(
   109  						flow.VersionBoundary{
   110  							BlockHeight: 1012,
   111  							Version:     "1.2.3",
   112  						}),
   113  				),
   114  			}
   115  			unittest.AddVersionBeacon(t, expectedVB.VersionBeacon, state)
   116  
   117  			expected := state.Final()
   118  			head, err := expected.Head()
   119  			require.NoError(t, err)
   120  
   121  			expectedVB.SealHeight = head.Height
   122  
   123  			actual, err := inmem.FromSnapshot(expected)
   124  			require.NoError(t, err)
   125  			assertSnapshotsEqual(t, expected, actual)
   126  			testEncodeDecode(t, actual)
   127  
   128  			actualVB, err := actual.VersionBeacon()
   129  			require.NoError(t, err)
   130  			require.Equal(t, expectedVB, actualVB)
   131  		})
   132  	})
   133  }
   134  
   135  // checks that a snapshot is equivalent after encoding and decoding
   136  func testEncodeDecode(t *testing.T, snap *inmem.Snapshot) {
   137  
   138  	bz, err := json.Marshal(snap.Encodable())
   139  	require.NoError(t, err)
   140  
   141  	var encoded inmem.EncodableSnapshot
   142  	err = json.Unmarshal(bz, &encoded)
   143  	require.NoError(t, err)
   144  
   145  	fromEncoded := inmem.SnapshotFromEncodable(encoded)
   146  	assertSnapshotsEqual(t, snap, fromEncoded)
   147  }
   148  
   149  // checks that 2 snapshots are equivalent by converting to a serializable
   150  // representation and comparing the serializations
   151  func snapshotsEqual(t *testing.T, snap1, snap2 protocol.Snapshot) bool {
   152  	enc1, err := inmem.FromSnapshot(snap1)
   153  	require.NoError(t, err)
   154  	enc2, err := inmem.FromSnapshot(snap2)
   155  	require.NoError(t, err)
   156  
   157  	bz1, err := json.Marshal(enc1.Encodable())
   158  	require.NoError(t, err)
   159  	bz2, err := json.Marshal(enc2.Encodable())
   160  	require.NoError(t, err)
   161  
   162  	return bytes.Equal(bz1, bz2)
   163  }
   164  
   165  func assertSnapshotsEqual(t *testing.T, snap1, snap2 protocol.Snapshot) {
   166  	assert.True(t, snapshotsEqual(t, snap1, snap2))
   167  }