F
Flow6mo ago
Bohao

Bohao | Flow (2024-05-11)

C1.0 - Will this code be handled during migration? Because this interface has been moved from MetadataViews to ViewResolver.
|
82 | let cap: Capability<&{ViewResolver.ResolverCollection}>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incompatible type annotations. expected `{MetadataViews.ResolverCollection}`, found `{ViewResolver.ResolverCollection}`

❌ Command Error: errors were found while attempting to perform preliminary validation of the contract code, and your contract HAS NOT been staged, however you can use the --skip-validation flag to bypass this check & stage the contract anyway
|
82 | let cap: Capability<&{ViewResolver.ResolverCollection}>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incompatible type annotations. expected `{MetadataViews.ResolverCollection}`, found `{ViewResolver.ResolverCollection}`

❌ Command Error: errors were found while attempting to perform preliminary validation of the contract code, and your contract HAS NOT been staged, however you can use the --skip-validation flag to bypass this check & stage the contract anyway
cap is a member of some resource.
28 Replies
Needle
Needle6mo ago
I've created a thread for your message. Please continue any relevant discussion in this thread. You can rename this thread using /title <new title> If this is a technical question that others may benefit from, considering also asking it on Stackoverflow: https://stackoverflow.com/questions/ask?tags=onflow-cadence
Bohao
Bohao6mo ago
I directly use --skip-validation for staging
Unknown User
Unknown User6mo ago
Message Not Public
Sign In & Join Server To View
Bohao
Bohao6mo ago
Another question is, Is removing inherited interface valid in the migration process? Just like From pub resource Vault: FungibleToken.Provider, FungibleToken.Receiver, FungibleToken.Balance, MetadataViews.Resolver to access(all) resource Vault: FungibleToken.Vault I'm not sure if this is specific treatment for Vault, NFT, Collection, or if it's the same for all Resources. cc @Bastian | Cadence
Unknown User
Unknown User6mo ago
Message Not Public
Sign In & Join Server To View
turbolent
turbolent6mo ago
Yes, all FT and NFT changes are handled. There are special rules in the migration and contract update checker Please see the migration guide on how to update FT and NFT contracts
Bohao
Bohao6mo ago
Actually, what I want to ask is whether other non-FT/NFT can also do this? That is, using the inherited Interface instead of the original lengthy interfaces(will replace some interfaces). If it's only for FT/NFT special rules, does that mean other Resources cannot? And the first question: after resource member Capability<&{MetadataViews.ResolverCollection}> modified to Capability<&{ViewResolver.ResolverCollection}>, an error occurred when staging. Is this a bug of flow-cli? or something wrong on my side?
turbolent
turbolent6mo ago
It’s only for code using the FT and NFT standard. We’ve added special rules so that the new V2 standards could be made even better Typo? The types before and after are the same, no?
Bohao
Bohao6mo ago
Except for the change in Type, everything else is the same. Since MetadataViews.ResolverCollection no longer exists, it must be changed to ViewResolver.ResolverCollection. This is a resource member
turbolent
turbolent6mo ago
yeah. this needs to be documented better in https://cadence-lang.org/docs/cadence-migration-guide/nft-guide, @joshua | Flow @Bohao | Flow can you please open an issue in https://github.com/onflow/cadence-lang.org/issues/new/choose ?
Bohao
Bohao6mo ago
actually the resource is not a NFT related... just using MetadataViews... Sure Sad.... I also want to simplify some other resources... It seems that I can only treat it as legacy code... Wait, a document issue I thought it might be a migration bug... 😂 If it is not possible to modify the Capability resource member's type in this way, does it mean that many of the resource members that existed as PrivateCap may have problems during Migration? Because their Type has been modified (from restricted Capability<&Resource{PrivateInterface}> to Capability<auth(Entitlement) &Resource>. Oh, maybe it's a little different. They are still the same type... Maybe only MetadataView has this problem. Capability<&{MetadataViews.ResolverCollection}> needs to be modified to Capability<&{ViewResolver.ResolverCollection}>, cc @joshua | Flow Daily asking... Is there an answer to the problem of migrating from Capability<&{MetadataViews.ResolverCollection}> to Capability<&{ViewResolver.ResolverCollection}>? @Bastian | Cadence @joshua | Flow
joshua
joshua6mo ago
There is no issue. You just need to change it in your code to be the correct type (ViewResolver.ResolverCollection) and the migrations will update it properly
Bohao
Bohao6mo ago
It is the correct type (ViewResolver.ResolverCollection)
No description
Bohao
Bohao6mo ago
I'm not sure if it will really be updated properly because it hasn't happened yet. But there was an error when staging with flow-cli.
Bohao
Bohao6mo ago
No description
Bohao
Bohao6mo ago
MetadataViews and ViewResolver are both at "testnet": "631e88ae7f1d7c20", that should be the correct contract address. but staging verification failed Probably, is it just a problem with flow-cli? cc @Chase | Flow 4D @Jordan R | Flow 4D
turbolent
turbolent6mo ago
we have a test case for this rewrite rule in the migration: https://github.com/onflow/flow-go/blob/63080cc17b1f633b0447166e47895bdd09c8549e/cmd/util/ledger/migrations/cadence_values_migration_test.go#L1406 Are you using the latest CLI prerelease?
Bohao
Bohao6mo ago
v1.18.0-cadence-v1.0.0-preview.23 I think it is.
Bohao
Bohao6mo ago
The test case is running: migrate method https://github.com/onflow/flow-go/blob/63080cc17b1f633b0447166e47895bdd09c8549e/cmd/util/ledger/migrations/cadence_values_migration_test.go#L972 But is the validator running checkTypeUpgradability method? I found this: https://github.com/onflow/cadence/blob/master/runtime/stdlib/cadence_v0.42_to_v1_contract_upgrade_validator.go#L402 I cannot find any specific case on MetadataViews then throw newTypeMismatchError
GitHub
cadence/runtime/stdlib/cadence_v0.42_to_v1_contract_upgrade_validat...
Cadence, the resource-oriented smart contract programming language 🏃‍♂️ - onflow/cadence
GitHub
flow-go/cmd/util/ledger/migrations/cadence_values_migration_test.go...
A fast, secure, and developer-friendly blockchain built to support the next generation of games, apps, and the digital assets that power them. - onflow/flow-go
turbolent
turbolent6mo ago
The rules for the NFT/FT types changes are in flow-go. Still the migration in flow-go should use the rules both for the state migration, and the update checker. Then there's also the CLI, which runs the update checker too to give some preliminary results, maybe that one isn't using the rules properly? @joshua | Flow do you happen to know if this is a general problem, i.e. are there other reports where ResolverCollection is causing problems? if there are alreafy updates staged that change ResolverCollection successfuly, it might be a problem on your end @Bohao | Flow
joshua
joshua6mo ago
I haven't heard of this problem before, but I don't think many people ever created capabilities of the type {ResolverCollection}, so there might not be any other examples.
turbolent
turbolent6mo ago
Do we have a similar problem for Resolver? we're setting up rules for both Resolver and ResolverCollection, from MetadataViews to ViewResolver (https://github.com/onflow/flow-go/blob/v0.34.0-crescendo-preview.18/cmd/util/ledger/migrations/cadence.go#L182-L183), here: https://github.com/onflow/flow-go/blob/v0.34.0-crescendo-preview.18/cmd/util/ledger/migrations/cadence.go#L22-L27 and we're using those rules in the update checker (https://github.com/onflow/flow-go/blob/v0.34.0-crescendo-preview.18/cmd/util/ledger/migrations/staged_contracts_migration.go#L642) which runs as part of the migration the CLI uses the same: https://github.com/onflow/flow-cli/blob/v1.18.0-cadence-v1.0.0-preview.23/internal/migrate/staging_validator.go#L170 @Bohao | Flow could you maybe provide a reproducer? ideally as small as possible
Bohao
Bohao6mo ago
Sure, here is a reproducer: Old Contract
/// The collection view resolver
///
access(all) resource CollectionViewResolver: MetadataViews.Resolver {
// FTView Resolver Collection Capability
access(self)
let cap: Capability<&AnyResource{MetadataViews.ResolverCollection}>
// FTView Id
access(self)
let id: UInt64

init(
_ cap: Capability<&AnyResource{MetadataViews.ResolverCollection}>,
id: UInt64
) {
pre {
cap.check(): "Collection view resolver capability is invalid"
}
post {
self.borrowViewResolver() != nil: "Collection view resolver is invalid"
}
self.cap = cap
self.id = id
// Ensure the collection view resolver is valid
self.borrowViewResolver()
}

// ---- Implementing the Resolver ----

access(all) view
fun getViews(): [Type] {
let viewResolver = self.borrowViewResolver()
return viewResolver?.getViews() ?? []
}

access(all) view
fun resolveView(_ view: Type): AnyStruct? {
let viewResolver = self.borrowViewResolver()
return viewResolver?.resolveView(view)
}

// ---- Local Methods ----

access(self) view
fun borrowViewResolver(): &AnyResource{MetadataViews.Resolver}? {
let ref = self.cap.borrow()
?? panic("Collection view resolver not found")
return ref.borrowViewResolver(id: self.id)
}
}
/// The collection view resolver
///
access(all) resource CollectionViewResolver: MetadataViews.Resolver {
// FTView Resolver Collection Capability
access(self)
let cap: Capability<&AnyResource{MetadataViews.ResolverCollection}>
// FTView Id
access(self)
let id: UInt64

init(
_ cap: Capability<&AnyResource{MetadataViews.ResolverCollection}>,
id: UInt64
) {
pre {
cap.check(): "Collection view resolver capability is invalid"
}
post {
self.borrowViewResolver() != nil: "Collection view resolver is invalid"
}
self.cap = cap
self.id = id
// Ensure the collection view resolver is valid
self.borrowViewResolver()
}

// ---- Implementing the Resolver ----

access(all) view
fun getViews(): [Type] {
let viewResolver = self.borrowViewResolver()
return viewResolver?.getViews() ?? []
}

access(all) view
fun resolveView(_ view: Type): AnyStruct? {
let viewResolver = self.borrowViewResolver()
return viewResolver?.resolveView(view)
}

// ---- Local Methods ----

access(self) view
fun borrowViewResolver(): &AnyResource{MetadataViews.Resolver}? {
let ref = self.cap.borrow()
?? panic("Collection view resolver not found")
return ref.borrowViewResolver(id: self.id)
}
}
After
/// The collection view resolver
///
access(all) resource CollectionViewResolver: ViewResolver.Resolver {
// FTView Resolver Collection Capability
access(self)
let cap: Capability<&{ViewResolver.ResolverCollection}>
// FTView Id
access(self)
let id: UInt64

init(
_ cap: Capability<&{ViewResolver.ResolverCollection}>,
id: UInt64
) {
pre {
cap.check(): "Collection view resolver capability is invalid"
}
post {
self.borrowViewResolver() != nil: "Collection view resolver is invalid"
}
self.cap = cap
self.id = id
// Ensure the collection view resolver is valid
self.borrowViewResolver()
}

// ---- Implementing the Resolver ----

access(all)
view fun getViews(): [Type] {
let viewResolver = self.borrowViewResolver()
return viewResolver?.getViews() ?? []
}

access(all)
fun resolveView(_ view: Type): AnyStruct? {
let viewResolver = self.borrowViewResolver()
return viewResolver?.resolveView(view)
}

// ---- Local Methods ----

access(self) view
fun borrowViewResolver(): &{ViewResolver.Resolver}? {
let ref = self.cap.borrow()
?? panic("Collection view resolver not found")
return ref.borrowViewResolver(id: self.id)
}
}
/// The collection view resolver
///
access(all) resource CollectionViewResolver: ViewResolver.Resolver {
// FTView Resolver Collection Capability
access(self)
let cap: Capability<&{ViewResolver.ResolverCollection}>
// FTView Id
access(self)
let id: UInt64

init(
_ cap: Capability<&{ViewResolver.ResolverCollection}>,
id: UInt64
) {
pre {
cap.check(): "Collection view resolver capability is invalid"
}
post {
self.borrowViewResolver() != nil: "Collection view resolver is invalid"
}
self.cap = cap
self.id = id
// Ensure the collection view resolver is valid
self.borrowViewResolver()
}

// ---- Implementing the Resolver ----

access(all)
view fun getViews(): [Type] {
let viewResolver = self.borrowViewResolver()
return viewResolver?.getViews() ?? []
}

access(all)
fun resolveView(_ view: Type): AnyStruct? {
let viewResolver = self.borrowViewResolver()
return viewResolver?.resolveView(view)
}

// ---- Local Methods ----

access(self) view
fun borrowViewResolver(): &{ViewResolver.Resolver}? {
let ref = self.cap.borrow()
?? panic("Collection view resolver not found")
return ref.borrowViewResolver(id: self.id)
}
}
flow.json, dependences:
"MetadataViews": {
"source": "./imports-c1/1d7e57aa55817448/MetadataViews.cdc",
"aliases": {
"emulator": "f8d6e0586b0a20c7",
"mainnet": "1d7e57aa55817448",
"testnet": "631e88ae7f1d7c20",
"previewnet": "b6763b4399a888c8"
}
},
"ViewResolver": {
"source": "./imports-c1/1d7e57aa55817448/ViewResolver.cdc",
"aliases": {
"emulator": "f8d6e0586b0a20c7",
"mainnet": "1d7e57aa55817448",
"testnet": "631e88ae7f1d7c20",
"previewnet": "b6763b4399a888c8"
}
},
"MetadataViews": {
"source": "./imports-c1/1d7e57aa55817448/MetadataViews.cdc",
"aliases": {
"emulator": "f8d6e0586b0a20c7",
"mainnet": "1d7e57aa55817448",
"testnet": "631e88ae7f1d7c20",
"previewnet": "b6763b4399a888c8"
}
},
"ViewResolver": {
"source": "./imports-c1/1d7e57aa55817448/ViewResolver.cdc",
"aliases": {
"emulator": "f8d6e0586b0a20c7",
"mainnet": "1d7e57aa55817448",
"testnet": "631e88ae7f1d7c20",
"previewnet": "b6763b4399a888c8"
}
},
I found that checkUserDefinedType only applied in case ast.NominalType, during the checkFields in the checkDeclarationUpdatability method.
// Step.1
checkFields(validator, oldDeclaration, newDeclaration)
// Step.2
checkNestedDeclarations(validator, oldDeclaration, newDeclaration, checkConformance)
// Step.3
if newDecl, ok := newDeclaration.(*ast.CompositeDeclaration); ok {
if oldDecl, ok := oldDeclaration.(*ast.CompositeDeclaration); ok {
checkConformance(oldDecl, newDecl)
}
}
// Step.1
checkFields(validator, oldDeclaration, newDeclaration)
// Step.2
checkNestedDeclarations(validator, oldDeclaration, newDeclaration, checkConformance)
// Step.3
if newDecl, ok := newDeclaration.(*ast.CompositeDeclaration); ok {
if oldDecl, ok := oldDeclaration.(*ast.CompositeDeclaration); ok {
checkConformance(oldDecl, newDecl)
}
}
The MetadataViews => ViewResolver is protected by checkUserDefinedType func. so checkConformance should be working. The only possible error is an error occurring during checkFields.
Unknown User
Unknown User6mo ago
Message Not Public
Sign In & Join Server To View
turbolent
turbolent6mo ago
@Supun | Cadence could you maybe have a look here, given you have a bit more knowledge and experience with the migration's update checker?
Unknown User
Unknown User6mo ago
Message Not Public
Sign In & Join Server To View
turbolent
turbolent6mo ago
@Jordan R | Flow 4D thanks for debugging and finding the issue 🙏
Unknown User
Unknown User6mo ago
Message Not Public
Sign In & Join Server To View
Want results from more Discord servers?
Add your server