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  }