github.com/onflow/flow-go@v0.33.17/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.RunWithFollowerProtocolState(t, rootSnapshot, func(db *badger.DB, state *bprotocol.FollowerState) { 27 28 epochBuilder := unittest.NewEpochBuilder(t, 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, err := state.Params().FinalizedRoot() 47 require.NoError(t, err) 48 expected := state.AtHeight(root.Height) 49 actual, err := inmem.FromSnapshot(expected) 50 require.NoError(t, err) 51 assertSnapshotsEqual(t, expected, actual) 52 testEncodeDecode(t, actual) 53 }) 54 55 // test getting an in-memory snapshot for all phase of epoch 1 56 t.Run("epoch 1", func(t *testing.T) { 57 t.Run("staking phase", func(t *testing.T) { 58 expected := state.AtHeight(epoch1.Staking) 59 actual, err := inmem.FromSnapshot(expected) 60 require.NoError(t, err) 61 assertSnapshotsEqual(t, expected, actual) 62 testEncodeDecode(t, actual) 63 }) 64 t.Run("setup phase", func(t *testing.T) { 65 expected := state.AtHeight(epoch1.Setup) 66 actual, err := inmem.FromSnapshot(expected) 67 require.NoError(t, err) 68 assertSnapshotsEqual(t, expected, actual) 69 testEncodeDecode(t, actual) 70 }) 71 t.Run("committed phase", func(t *testing.T) { 72 expected := state.AtHeight(epoch1.Committed) 73 actual, err := inmem.FromSnapshot(expected) 74 require.NoError(t, err) 75 assertSnapshotsEqual(t, expected, actual) 76 testEncodeDecode(t, actual) 77 }) 78 }) 79 80 // test getting an in-memory snapshot for all phase of epoch 2 81 t.Run("epoch 2", func(t *testing.T) { 82 t.Run("staking phase", func(t *testing.T) { 83 expected := state.AtHeight(epoch2.Staking) 84 actual, err := inmem.FromSnapshot(expected) 85 require.NoError(t, err) 86 assertSnapshotsEqual(t, expected, actual) 87 testEncodeDecode(t, actual) 88 }) 89 t.Run("setup phase", func(t *testing.T) { 90 expected := state.AtHeight(epoch2.Setup) 91 actual, err := inmem.FromSnapshot(expected) 92 require.NoError(t, err) 93 assertSnapshotsEqual(t, expected, actual) 94 testEncodeDecode(t, actual) 95 }) 96 t.Run("committed phase", func(t *testing.T) { 97 expected := state.AtHeight(epoch2.Committed) 98 actual, err := inmem.FromSnapshot(expected) 99 require.NoError(t, err) 100 assertSnapshotsEqual(t, expected, actual) 101 testEncodeDecode(t, actual) 102 }) 103 }) 104 105 // ensure last version beacon is included 106 t.Run("version beacon", func(t *testing.T) { 107 108 expectedVB := &flow.SealedVersionBeacon{ 109 VersionBeacon: unittest.VersionBeaconFixture( 110 unittest.WithBoundaries( 111 flow.VersionBoundary{ 112 BlockHeight: 1012, 113 Version: "1.2.3", 114 }), 115 ), 116 } 117 unittest.AddVersionBeacon(t, expectedVB.VersionBeacon, state) 118 119 expected := state.Final() 120 head, err := expected.Head() 121 require.NoError(t, err) 122 123 expectedVB.SealHeight = head.Height 124 125 actual, err := inmem.FromSnapshot(expected) 126 require.NoError(t, err) 127 assertSnapshotsEqual(t, expected, actual) 128 testEncodeDecode(t, actual) 129 130 actualVB, err := actual.VersionBeacon() 131 require.NoError(t, err) 132 require.Equal(t, expectedVB, actualVB) 133 }) 134 }) 135 } 136 137 // checks that a snapshot is equivalent after encoding and decoding 138 func testEncodeDecode(t *testing.T, snap *inmem.Snapshot) { 139 140 bz, err := json.Marshal(snap.Encodable()) 141 require.NoError(t, err) 142 143 var encoded inmem.EncodableSnapshot 144 err = json.Unmarshal(bz, &encoded) 145 require.NoError(t, err) 146 147 fromEncoded := inmem.SnapshotFromEncodable(encoded) 148 assertSnapshotsEqual(t, snap, fromEncoded) 149 } 150 151 // checks that 2 snapshots are equivalent by converting to a serializable 152 // representation and comparing the serializations 153 func snapshotsEqual(t *testing.T, snap1, snap2 protocol.Snapshot) bool { 154 enc1, err := inmem.FromSnapshot(snap1) 155 require.NoError(t, err) 156 enc2, err := inmem.FromSnapshot(snap2) 157 require.NoError(t, err) 158 159 bz1, err := json.Marshal(enc1.Encodable()) 160 require.NoError(t, err) 161 bz2, err := json.Marshal(enc2.Encodable()) 162 require.NoError(t, err) 163 164 return bytes.Equal(bz1, bz2) 165 } 166 167 func assertSnapshotsEqual(t *testing.T, snap1, snap2 protocol.Snapshot) { 168 assert.True(t, snapshotsEqual(t, snap1, snap2)) 169 }