Skip to content

Conversation

Jim8y
Copy link
Contributor

@Jim8y Jim8y commented Sep 22, 2025

  • Harden NEP-25 support by validating ExtendedType metadata according to the spec (length/forbidnull/
    interface/key/value/fields/namedtype usage, array element requirements, named type existence).
    • Propagate the validation across ABI parsing paths (ContractAbi, ContractMethodDescriptor,
      ContractEventDescriptor, ContractParameterDefinition) for both JSON and stack deserialization,
      blocking mismatched parameter/return declarations.
    • Add regression coverage in UT_ContractManifest for mismatched extended types and missing named
      types to ensure invalid manifests are rejected.

@Jim8y Jim8y force-pushed the nep-25-extendedtype-validation branch from 256d956 to 1bce361 Compare September 22, 2025 06:16
NEP-25 adds ExtendedType descriptors to contract manifests, but the branch currently accepts manifests that reference undefined named types, mismatch parameter metadata, or break the base NEP-25 rules. This commit adds ExtendedType validation to ContractAbi, ContractMethodDescriptor, and ContractParameterDefinition so contracts that violate NEP-25 are rejected before deployment.\n\nThe change keeps the detailed FormatException messages recently introduced in dev, ensuring operators get actionable errors while we enforce the extended-type invariants.
@Jim8y Jim8y force-pushed the nep-25-extendedtype-validation branch from 1bce361 to 12da30f Compare September 22, 2025 06:18
Copy link
Contributor

@roman-khimov roman-khimov left a comment

Choose a reason for hiding this comment

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

Overall this should work.

ValidateCore(expectedType: null, allowFields: true, knownNamedTypes, allowNamedTypeReference: true);
}

private void ValidateCore(ContractParameterType? expectedType, bool allowFields, ISet<string>? knownNamedTypes, bool allowNamedTypeReference)
Copy link
Contributor

Choose a reason for hiding this comment

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

allowNamedTypeReference is always true

NamedType = json["namedtype"]?.GetString(),
};
if (!Enum.IsDefined(typeof(ContractParameterType), type.Type)) throw new FormatException();
if (type.Type == ContractParameterType.Void) throw Nep25Error("Void type is not allowed.");
Copy link
Contributor

Choose a reason for hiding this comment

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

Somewhat duplicating ValdateCore


if (Type == ContractParameterType.Map && !Key.HasValue)
throw Nep25Error("key is required for Map type.");

Copy link
Contributor

Choose a reason for hiding this comment

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

Many of the checks are context-independent (can be performed on a single ExtendedType value), so can be done at ExtendedType.FromJSON/FromStackItem level. But that's just a suggestion, functionally ABI-level checks can be sufficient.

ContractParameterType.String
};

private static FormatException Nep25Error(string message) => new($"Invalid NEP-25 extended type: {message}");
Copy link
Member

Choose a reason for hiding this comment

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

I dont like this approach.

Copy link
Contributor

Choose a reason for hiding this comment

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

But why? And what's the alternative?

Copy link
Member

@cschuchardt88 cschuchardt88 Sep 22, 2025

Choose a reason for hiding this comment

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

There are many alternatives. But the simplest is to just use throw new FormatException($"Invalid NEP-25 extended type: {message}") instead of a function. But I would prefer to use an exception class with the name Nep25TypeException. The reason for this is when you throw Nep25Error(message) you dont know the exception at hand and can make it hard to track down when debugging. Makes you have to look at Call Stack...etc. It just harder to maintain.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants