github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/cmd/util/ledger/migrations/fix_broken_data_migration_test.go (about) 1 package migrations 2 3 import ( 4 "bytes" 5 "context" 6 "encoding/hex" 7 "testing" 8 9 "github.com/onflow/cadence/runtime/common" 10 "github.com/rs/zerolog" 11 "github.com/stretchr/testify/assert" 12 "github.com/stretchr/testify/require" 13 14 "github.com/onflow/flow-go/cmd/util/ledger/util" 15 "github.com/onflow/flow-go/cmd/util/ledger/util/registers" 16 "github.com/onflow/flow-go/ledger" 17 ) 18 19 func TestFixSlabsWithBrokenReferences(t *testing.T) { 20 t.Parallel() 21 22 const nWorker = 2 23 24 rawAddress := mustDecodeHex("5e3448b3cffb97f2") 25 26 address := common.MustBytesToAddress(rawAddress) 27 28 ownerKey := ledger.KeyPart{Type: 0, Value: rawAddress} 29 30 oldPayloads := []*ledger.Payload{ 31 // account status "a.s" register 32 ledger.NewPayload( 33 ledger.NewKey([]ledger.KeyPart{ownerKey, {Type: 2, Value: mustDecodeHex("612e73")}}), 34 mustDecodeHex("00000000000000083900000000000000090000000000000001"), 35 ), 36 37 // storage domain register 38 ledger.NewPayload( 39 ledger.NewKey([]ledger.KeyPart{ownerKey, {Type: 2, Value: mustDecodeHex("73746f72616765")}}), 40 mustDecodeHex("0000000000000008"), 41 ), 42 43 // public domain register 44 ledger.NewPayload( 45 ledger.NewKey([]ledger.KeyPart{ownerKey, {Type: 2, Value: mustDecodeHex("7075626c6963")}}), 46 mustDecodeHex("0000000000000007"), 47 ), 48 49 // MapDataSlab [balance:1000.00089000 uuid:13797744] 50 ledger.NewPayload( 51 ledger.NewKey([]ledger.KeyPart{ownerKey, {Type: 2, Value: mustDecodeHex("240000000000000001")}}), 52 mustDecodeHex("008883d88483d8c082487e60df042a9c086869466c6f77546f6b656e6f466c6f77546f6b656e2e5661756c7402021b146e6a6a4c5eee08008883005b00000000000000100887f9d0544c60cbefe0afc51d7f46609b0000000000000002826762616c616e6365d8bc1b00000017487843a8826475756964d8a41a00d28970"), 53 ), 54 55 // MapDataSlab [uuid:13799884 roles:StorageIDStorable({[94 52 72 179 207 251 151 242] [0 0 0 0 0 0 0 3]}) recipient:0x5e3448b3cffb97f2] 56 ledger.NewPayload( 57 ledger.NewKey([]ledger.KeyPart{ownerKey, {Type: 2, Value: mustDecodeHex("240000000000000002")}}), 58 mustDecodeHex("00c883d88483d8c0824848602d8056ff9d937046616e546f705065726d697373696f6e7746616e546f705065726d697373696f6e2e486f6c64657202031bb9d0e9f36650574100c883005b000000000000001820d6c23f2e85e694b0070dbc21a9822de5725916c4a005e99b0000000000000003826475756964d8a41a00d291cc8265726f6c6573d8ff505e3448b3cffb97f200000000000000038269726563697069656e74d883485e3448b3cffb97f2"), 59 ), 60 61 // This slab contains broken references. 62 // MapDataSlab [StorageIDStorable({[0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 45]}):Capability<&A.48602d8056ff9d93.FanTopPermission.Admin>(address: 0x48602d8056ff9d93, path: /private/FanTopAdmin)] 63 ledger.NewPayload( 64 ledger.NewKey([]ledger.KeyPart{ownerKey, {Type: 2, Value: mustDecodeHex("240000000000000003")}}), 65 mustDecodeHex("00c883d8d982d8d582d8c0824848602d8056ff9d937046616e546f705065726d697373696f6e7546616e546f705065726d697373696f6e2e526f6c65d8ddf6011b535c9de83a38cab000c883005b000000000000000856c1dcdf34d761b79b000000000000000182d8ff500000000000000000000000000000002dd8c983d8834848602d8056ff9d93d8c882026b46616e546f7041646d696ed8db82f4d8d582d8c0824848602d8056ff9d937046616e546f705065726d697373696f6e7646616e546f705065726d697373696f6e2e41646d696e"), 66 ), 67 68 // MapDataSlab [resources:StorageIDStorable({[94 52 72 179 207 251 151 242] [0 0 0 0 0 0 0 5]}) uuid:15735719 address:0x5e3448b3cffb97f2] 69 ledger.NewPayload( 70 ledger.NewKey([]ledger.KeyPart{ownerKey, {Type: 2, Value: mustDecodeHex("240000000000000004")}}), 71 mustDecodeHex("00c883d88483d8c0824848602d8056ff9d937346616e546f705065726d697373696f6e563261781a46616e546f705065726d697373696f6e5632612e486f6c64657202031b5a99ef3adb06d40600c883005b00000000000000185c9fead93697b692967de568f789d3c2d5e974502c8b12e99b000000000000000382697265736f7572636573d8ff505e3448b3cffb97f20000000000000005826475756964d8a41a00f01ba7826761646472657373d883485e3448b3cffb97f2"), 72 ), 73 74 // MapDataSlab ["admin":StorageIDStorable({[94 52 72 179 207 251 151 242] [0 0 0 0 0 0 0 6]})] 75 ledger.NewPayload( 76 ledger.NewKey([]ledger.KeyPart{ownerKey, {Type: 2, Value: mustDecodeHex("240000000000000005")}}), 77 mustDecodeHex("00c883d8d982d8d408d8dc82d8d40581d8d682d8c0824848602d8056ff9d937346616e546f705065726d697373696f6e563261781846616e546f705065726d697373696f6e5632612e526f6c65011b8059ccce9aa48cfb00c883005b00000000000000087a89c005baa53d9a9b000000000000000182d8876561646d696ed8ff505e3448b3cffb97f20000000000000006"), 78 ), 79 80 // MapDataSlab [role:"admin" uuid:15735727] 81 ledger.NewPayload( 82 ledger.NewKey([]ledger.KeyPart{ownerKey, {Type: 2, Value: mustDecodeHex("240000000000000006")}}), 83 mustDecodeHex("008883d88483d8c0824848602d8056ff9d937346616e546f705065726d697373696f6e563261781946616e546f705065726d697373696f6e5632612e41646d696e02021b4fc212cd0f233183008883005b0000000000000010858862f5e3e45e48d2bf75097a8aaf819b00000000000000028264726f6c65d8876561646d696e826475756964d8a41a00f01baf"), 84 ), 85 86 // MapDataSlab [ 87 // FanTopPermissionV2a:PathLink<&{A.48602d8056ff9d93.FanTopPermissionV2a.Receiver}>(/storage/FanTopPermissionV2a) 88 // flowTokenReceiver:PathLink<&{A.9a0766d93b6608b7.FungibleToken.Receiver}>(/storage/flowTokenVault) 89 // flowTokenBalance:PathLink<&{A.9a0766d93b6608b7.FungibleToken.Balance}>(/storage/flowTokenVault) 90 // FanTopPermission:PathLink<&{A.48602d8056ff9d93.FanTopPermission.Receiver}>(/storage/FanTopPermission)] 91 ledger.NewPayload( 92 ledger.NewKey([]ledger.KeyPart{ownerKey, {Type: 2, Value: mustDecodeHex("240000000000000007")}}), 93 mustDecodeHex("008883f6041bc576c5f201b94974008883005b00000000000000207971082fb163397089dbafb546246f429beff1dc622768dcb916d25455dc0be39b0000000000000004827346616e546f705065726d697373696f6e563261d8cb82d8c882017346616e546f705065726d697373696f6e563261d8db82f4d8dc82d8d40581d8d682d8c0824848602d8056ff9d937346616e546f705065726d697373696f6e563261781c46616e546f705065726d697373696f6e5632612e52656365697665728271666c6f77546f6b656e5265636569766572d8cb82d8c882016e666c6f77546f6b656e5661756c74d8db82f4d8dc82d8d582d8c082487e60df042a9c086869466c6f77546f6b656e6f466c6f77546f6b656e2e5661756c7481d8d682d8c082489a0766d93b6608b76d46756e6769626c65546f6b656e7646756e6769626c65546f6b656e2e52656365697665728270666c6f77546f6b656e42616c616e6365d8cb82d8c882016e666c6f77546f6b656e5661756c74d8db82f4d8dc82d8d582d8c082487e60df042a9c086869466c6f77546f6b656e6f466c6f77546f6b656e2e5661756c7481d8d682d8c082489a0766d93b6608b76d46756e6769626c65546f6b656e7546756e6769626c65546f6b656e2e42616c616e6365827046616e546f705065726d697373696f6ed8cb82d8c882017046616e546f705065726d697373696f6ed8db82f4d8dc82d8d40581d8d682d8c0824848602d8056ff9d937046616e546f705065726d697373696f6e781946616e546f705065726d697373696f6e2e5265636569766572"), 94 ), 95 96 // MapDataSlab [ 97 // FanTopPermission:StorageIDStorable({[94 52 72 179 207 251 151 242] [0 0 0 0 0 0 0 2]}) 98 // FanTopPermissionV2a:StorageIDStorable({[94 52 72 179 207 251 151 242] [0 0 0 0 0 0 0 4]}) 99 // flowTokenVault:StorageIDStorable({[94 52 72 179 207 251 151 242] [0 0 0 0 0 0 0 1]})] 100 ledger.NewPayload( 101 ledger.NewKey([]ledger.KeyPart{ownerKey, {Type: 2, Value: mustDecodeHex("240000000000000008")}}), 102 mustDecodeHex("008883f6031b7d303e276f3b803f008883005b00000000000000180a613a86f5856a480b3a715aa29b9876e5d7742a5a1df8e09b0000000000000003827046616e546f705065726d697373696f6ed8ff505e3448b3cffb97f20000000000000002827346616e546f705065726d697373696f6e563261d8ff505e3448b3cffb97f20000000000000004826e666c6f77546f6b656e5661756c74d8ff505e3448b3cffb97f20000000000000001"), 103 ), 104 } 105 106 slabIndexWithBrokenReferences := mustDecodeHex("240000000000000003") 107 108 slabWithBrokenReferences := ledger.NewPayload( 109 ledger.NewKey([]ledger.KeyPart{ownerKey, {Type: 2, Value: slabIndexWithBrokenReferences}}), 110 mustDecodeHex("00c883d8d982d8d582d8c0824848602d8056ff9d937046616e546f705065726d697373696f6e7546616e546f705065726d697373696f6e2e526f6c65d8ddf6011b535c9de83a38cab000c883005b000000000000000856c1dcdf34d761b79b000000000000000182d8ff500000000000000000000000000000002dd8c983d8834848602d8056ff9d93d8c882026b46616e546f7041646d696ed8db82f4d8d582d8c0824848602d8056ff9d937046616e546f705065726d697373696f6e7646616e546f705065726d697373696f6e2e41646d696e"), 111 ) 112 113 fixedSlabWithBrokenReferences := ledger.NewPayload( 114 ledger.NewKey([]ledger.KeyPart{ownerKey, {Type: 2, Value: slabIndexWithBrokenReferences}}), 115 ledger.Value(mustDecodeHex("108883d8d982d8d582d8c0824848602d8056ff9d937046616e546f705065726d697373696f6e7546616e546f705065726d697373696f6e2e526f6c65d8ddf6001b535c9de83a38cab08300590000990000")), 116 ) 117 118 // Account status register is updated to include address ID counter and new storage used. 119 accountStatusRegisterID := mustDecodeHex("612e73") 120 updatedAccountStatusRegister := ledger.NewPayload( 121 ledger.NewKey([]ledger.KeyPart{ownerKey, {Type: 2, Value: accountStatusRegisterID}}), 122 ledger.Value([]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}), 123 ) 124 125 expectedNewPayloads := make([]*ledger.Payload, len(oldPayloads)) 126 copy(expectedNewPayloads, oldPayloads) 127 128 for i, payload := range expectedNewPayloads { 129 payloadKey, err := payload.Key() 130 require.NoError(t, err) 131 132 key := payloadKey.KeyParts[1].Value 133 134 if bytes.Equal(key, slabIndexWithBrokenReferences) { 135 expectedNewPayloads[i] = fixedSlabWithBrokenReferences 136 } else if bytes.Equal(key, accountStatusRegisterID) { 137 expectedNewPayloads[i] = updatedAccountStatusRegister 138 } 139 } 140 141 rwf := &testReportWriterFactory{} 142 143 log := zerolog.New(zerolog.NewTestWriter(t)) 144 145 accountsToFix := map[common.Address]struct{}{ 146 address: {}, 147 } 148 149 migration := NewFixBrokenReferencesInSlabsMigration(t.TempDir(), rwf, accountsToFix) 150 151 registersByAccount, err := registers.NewByAccountFromPayloads(oldPayloads) 152 require.NoError(t, err) 153 154 err = migration.InitMigration(log, registersByAccount, nWorker) 155 require.NoError(t, err) 156 157 accountRegisters := registersByAccount.AccountRegisters(string(address[:])) 158 159 err = migration.MigrateAccount( 160 context.Background(), 161 address, 162 accountRegisters, 163 ) 164 require.NoError(t, err) 165 166 err = migration.Close() 167 require.NoError(t, err) 168 169 newPayloads := registersByAccount.DestructIntoPayloads(nWorker) 170 171 require.Equal(t, len(expectedNewPayloads), len(newPayloads)) 172 173 for _, expected := range expectedNewPayloads { 174 k, _ := expected.Key() 175 rawExpectedKey := expected.EncodedKey() 176 177 var found bool 178 for _, p := range newPayloads { 179 if bytes.Equal(rawExpectedKey, p.EncodedKey()) { 180 found = true 181 require.Equal(t, expected.Value(), p.Value(), k.String()) 182 break 183 } 184 } 185 require.True(t, found) 186 } 187 188 writer := rwf.reportWriters[fixSlabsWithBrokenReferencesName] 189 assert.Equal(t, 190 []any{ 191 fixedSlabsWithBrokenReferences{ 192 Account: address.Hex(), 193 BrokenPayloads: []*ledger.Payload{slabWithBrokenReferences}, 194 FixedPayloads: []*ledger.Payload{fixedSlabWithBrokenReferences}, 195 }, 196 }, 197 writer.entries, 198 ) 199 200 readIsPartial, readBrokenPayloads, err := util.ReadPayloadFile(log, migration.payloadsFile) 201 require.NoError(t, err) 202 assert.True(t, readIsPartial) 203 assert.Equal(t, []*ledger.Payload{slabWithBrokenReferences}, readBrokenPayloads) 204 } 205 206 func mustDecodeHex(s string) []byte { 207 b, err := hex.DecodeString(s) 208 if err != nil { 209 panic(err) 210 } 211 return b 212 }