Skip to content

Conversation

@shargon
Copy link
Member

@shargon shargon commented Jul 2, 2025

Description

Implement NEP-25 neo-project/proposals#160 (review)
Replace of #3272

Type of change

  • Optimization (the change is only an optimization)
  • Style (the change is only a code style for better maintenance or standard purpose)
  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How Has This Been Tested?

  • Test A
  • Test B

Test Configuration:

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

@superboyiii superboyiii mentioned this pull request Jul 24, 2025
@shargon shargon marked this pull request as ready for review July 30, 2025 09:15
ajara87
ajara87 previously approved these changes Jul 31, 2025
shargon and others added 5 commits August 3, 2025 11:53
- Document all implemented features and components
- Add usage examples for different type definitions
- Confirm backward compatibility with NEP-14
- Mark implementation as complete and tested
- Update FromStackItem_ShouldHandleNullFields test to include all 8 fields
- Update ToStackItem_ShouldProduceNullFields test to expect 8 fields
- Tests now match the actual ExtendedType implementation which uses 8 fields
ajara87
ajara87 previously approved these changes Oct 14, 2025
Copy link
Member

@ajara87 ajara87 left a comment

Choose a reason for hiding this comment

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

LGTM

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.

How about circular references in namedtypes?

"namedtypes": {
    "boo": {
        "type": "Array",
        "namedtype": "boo"
    }
}

- Roman's review: Remove duplicate checks
@shargon
Copy link
Member Author

shargon commented Oct 18, 2025

How about circular references in namedtypes?

"namedtypes": {
    "boo": {
        "type": "Array",
        "namedtype": "boo"
    }
}

I think that now it's solved

@shargon
Copy link
Member Author

shargon commented Oct 23, 2025

According to the meeting circular check will be changed

@shargon
Copy link
Member Author

shargon commented Oct 24, 2025

@ajara87 could you ad an UT for this case:

FAIL:

"namedtypes": {
    "boo": {
        "type": "Array",
        "namedtype": "boo"
    }
}

I think should be solved know

@ajara87
Copy link
Member

ajara87 commented Oct 26, 2025

@ajara87 could you ad an UT for this case:

FAIL:

"namedtypes": {
    "boo": {
        "type": "Array",
        "namedtype": "boo"
    }
}

I think should be solved know

@shargon @roman-khimov Should work this case?

"namedtypes": {
    "boo": {
        "type": "Array",
        "namedtype": "alice"
    },
   "alice": {
        "type": "Array",
        "namedtype": "boo"
    }
}

@roman-khimov
Copy link
Contributor

@shargon @roman-khimov Should work this case?

"namedtypes": {
    "boo": {
        "type": "Array",
        "namedtype": "alice"
    },
   "alice": {
        "type": "Array",
        "namedtype": "boo"
    }
}

No. Top-level namedtype can't reference another namedtype. Inner fields/values/whatever of it can.

@ajara87
Copy link
Member

ajara87 commented Oct 26, 2025

"namedtypes": {
    "boo": {
        "type": "Array",
        "namedtype": "boo"
    }
}

Thank you @roman-khimov. If I understand correctly the following should result:

Examples that should fail due to invalid format

"namedtypes": {
    "boo": {
        "type": "Array",
        "namedtype": "boo"
    }
}

"namedtypes": {
    "boo": {
        "type": "Array",
        "namedtype": "alice"
    },
   "alice": {
        "type": "Array",
        "namedtype": "boo"
    }
}

Example that should fail due to circular reference

"namedtypes": {
    "boo": {
        "type": "Array",
        "value": { "namedtype": "boo" }
    }
}

"namedtypes": {
    "boo": {
        "type": "Array",
        "value": { "namedtype": "alice" }
    },
    "alice": {
        "type": "Array",
        "value": { "namedtype": "boo" }
    }
}

Example should be successful

"namedtypes": {
    "boo": {
        "type": "Array",
        "value": { "namedtype": "alice" }
    },
    "alice": {
        "type": "Array",
        "value": { "type": "Integer" }
    }
}

@roman-khimov
Copy link
Contributor

Example that should fail due to circular reference

"namedtypes": {
    "boo": {
        "type": "Array",
        "value": { "namedtype": "boo" }
    }
}

"namedtypes": {
    "boo": {
        "type": "Array",
        "value": { "namedtype": "alice" }
    },
    "alice": {
        "type": "Array",
        "value": { "namedtype": "boo" }
    }
}

These are valid to me. Not meaningful, like an array of abstract pointers, but not breaking anything either.

* Extend ValidateExtendedTypes to check circle references

* remove unused usings

* Add more tests and change enum

* Add assert to valid tests
Comment on lines +69 to +72
if (NamedTypes != null)
{
ret.Add(new Map(NamedTypes.ToDictionary(p => (PrimitiveType)p.Key, p => (StackItem)p.Value.ToStackItem(referenceCounter)), referenceCounter));
}
Copy link
Member

Choose a reason for hiding this comment

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

I have a concern: manifest serialization format doesn't depend on hardforks, and we don't change native Management in any way. It means that there's a tiny possibility of a statediff during an update to this version: if someone deploys contract with extended types, then deployment transaction will fail on old nodes and will succeed on updated nodes.

This fact may probably be ignored, but at least we should know about it.

Copy link
Member Author

Choose a reason for hiding this comment

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

If they don't update the node, the state difference will come later, isn't it?

Copy link
Member

Choose a reason for hiding this comment

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

the state difference will come later,

At Faun height, due to other Faun-specific updates, right. But my concern is that with the current implementation state difference may happen even before Faun if someone submits extended manifest to the chain on contract deploy/update.

Comment on lines +29 to +34
private static readonly HashSet<ContractParameterType> s_lengthAllowedTypes =
[
ContractParameterType.Integer,
ContractParameterType.ByteArray,
ContractParameterType.String,
ContractParameterType.Array
Copy link
Member

Choose a reason for hiding this comment

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

The implementation matches proposal. However, I think we may consider adding ContractParameterType.Map to this list since maps also have length.

When used it specifies the maximum possible byte length of an integer/byte array/string or number of array elements.

So effectively, map's length is the number of key-value pairs in this map. @roman-khimov, what do you think?

Comment on lines 488 to 489
if (Type == ContractParameterType.Array && NamedType is null && (Fields is null || Fields.Length == 0))
throw Nep25Error("value, namedtype or fields must be provided for Array type to describe element type.");
Copy link
Member

Choose a reason for hiding this comment

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

I think it's allowed to have named structure with zero number of fields. It's an edge-case, but it's not prohibited by the standard directly.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done, please check the last changes

Comment on lines 454 to 455
if (Length.HasValue || ForbidNull.HasValue || Interface.HasValue || Key.HasValue || Value is not null || (Fields is not null && Fields.Length > 0))
throw Nep25Error("namedtype cannot be combined with other modifiers.");
Copy link
Member

Choose a reason for hiding this comment

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

Ditto here, looks like Fields is not null && Fields.Length > 0 check may be reduced to Fields is not null.

Comment on lines 466 to 467
if (Fields is not null && Fields.Length > 0)
throw Nep25Error("value and fields cannot be used together.");
Copy link
Member

Choose a reason for hiding this comment

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

And probably here.

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

Labels

Critical Issues (bugs) that need to be fixed ASAP Waiting for Review

Projects

None yet

Development

Successfully merging this pull request may close these issues.