Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace hash-based validation of migrated Cadence values to use Equal() #5204

Conversation

fxamacker
Copy link
Member

@fxamacker fxamacker commented Jan 5, 2024

Updates PR #4633
Updates #4576
Updates onflow/cadence#2983

This change replaces hash-based validation of Cadence values in PR #4633 in order to prepare for atree inlining to be incorporated into the migration program.

Also added --validate flag to enable validation during migration since enabling validation can increase duration of migration.

Enabling validation will use cadence.Equal() to compare every Cadence value before/after migration.

This change replaces hash-based validation of Cadence values
in order to prepare for atree inlining to be incorporated
into the migration program.

Also added validate flag to enable validation during migration
since enabling validation can increase duration of migration.
@fxamacker fxamacker changed the title Replace hash-based validation of migrated Cadence values to use ` Replace hash-based validation of migrated Cadence values to use Equal() Jan 5, 2024
}

// NoopRuntimeInterface is a runtime interface that can be used in migrations.
type NoopRuntimeInterface struct {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we reuse MigrationRuntimeInterface so we dont have to create a new one?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't reuse MigrationRuntimeInterface code because it contains many fields that are not needed and I wanted to avoid complications if we need to make modifications.

On the other hand, we might be able to reuse NoopRuntimeInterface because it is bare.

newValue := newStorageMap.ReadValue(nopMemoryGauge, interpreter.StringStorageMapKey(stringKey))

if !cadenceValueEqual(oldRuntime.Interpreter, oldValue, newRuntime.Interpreter, newValue) {
return fmt.Errorf("failed to validate domain %s, key %s: old value %v (%T), new value %v (%T)", domain, key, oldValue, oldValue, newValue, newValue)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What will happen here if the value is a 100GB cadence value...

Would it be better to only log the deepest most difference instead of the outermost?

i.e. if difference is in

  • composite A:
    • array B:
      • element 2:
        • Composite C:
          • field D

we would log something like: "A.B[2].C.D (which is 'asdf') is different from A'.B'[2].C'.D' (which is 'asdfg')"
instead of entire A and entire A'

But then again, this is only relevant if we actually find a difference, so it might be premature to think about this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point! Done in 706b5a5:

  • default: modified error message to include trace and only include values at the deepest level.
  • non-default flag: --log-verbose-validation-error enables logging of entire Cadence values on validation error during atree migration.

For example, this is a test snippet for non-verbose error msg and verbose error log:

wantErrorMsg := "failed to validate value for address 0000000000000001, domain storage, key 0: failed to validate ([AnyStruct][0]).([UInt64][1]): values differ: 1 (interpreter.UInt64Value) != 2 (interpreter.UInt64Value)"

wantVerboseMsg := "{\"level\":\"info\",\"address\":\"0000000000000001\",\"domain\":\"storage\",\"key\":\"0\",\"trace\":\"failed to validate ([AnyStruct][0]).([UInt64][1]): values differ: 1 (interpreter.UInt64Value) != 2 (interpreter.UInt64Value)\",\"old value\":\"[[0, 1]]\",\"new value\":\"[[0, 2]]\",\"message\":\"failed to validate value\"}\n"

cmd/util/cmd/execution-state-extract/cmd.go Show resolved Hide resolved
cmd/util/cmd/execution-state-extract/cmd.go Outdated Show resolved Hide resolved
@janezpodhostnik
Copy link
Contributor

Great work. I'm a bit concerned with the. validation output, but thats not actually a problem if the validation passes (which it should in the end) but it might be a bit problematic while we are still debugging.

}

// Iterate through all domains and compare cadence values.
for _, domain := range domains {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we let the caller pass the domains as an argument?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea but in this case, it's not needed because we only deal with a hard coded set of domains defined in migration PR 4633.

cmd/util/ledger/migrations/cadence_value_validation.go Outdated Show resolved Hide resolved
return false
}

if !v.StaticType(vInterpreter).Equal(otherComposite.StaticType(otherInterpreter)) ||
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to confirm, passing this check means v and other have the same fields, right? In other words, no need to check if other has additional fields that v doesn't have?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great catch! 👍

StaticType doesn't check fields, so I added a temporary workaround for this.

I'll open PR to improve this workaround when Cadence PR 3002 is merged and the function I requested becomes available.

Added flag --log-verbose-validation-error to enable logging of entire
Cadence values on validation error during atree migration.
This is a temporary (and inefficient) workaround to check number
of fields in Cadence CompositeValue.

In the future, CompositeValue.FieldCount() will be added to
Cadence, so that function can be used to improve this workaround.
@fxamacker
Copy link
Member Author

@janezpodhostnik

Great work. I'm a bit concerned with the. validation output, but thats not actually a problem if the validation passes (which it should in the end) but it might be a bit problematic while we are still debugging.

Good point! I improved this and described it at #5204 (comment) to have non-verbose default and a flag for more verbose logging:

  • default: modified error message to include trace and only include values at the deepest level.
  • non-default flag: --log-verbose-validation-error enables logging of entire Cadence values on validation error during atree migration.

Although I'm merging this PR to unblock others, it would be great if you can take a look at this change to logging/tracing.

@fxamacker fxamacker merged commit 00cdc35 into janez/atree-migration Jan 9, 2024
@fxamacker fxamacker deleted the fxamacker/atree-migration-cadence-value-validation branch January 9, 2024 20:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants