From 668dd940334f4adc15a605047ca3b4f6aa557045 Mon Sep 17 00:00:00 2001 From: Harry Pierson Date: Sun, 26 Jun 2022 09:24:39 -0700 Subject: [PATCH 1/2] SSP debug info --- nep-19.mediawiki | 420 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 374 insertions(+), 46 deletions(-) diff --git a/nep-19.mediawiki b/nep-19.mediawiki index 207a3296..3f24d046 100644 --- a/nep-19.mediawiki +++ b/nep-19.mediawiki @@ -3,13 +3,15 @@ Title: Debug Info Specification Author: Harry Pierson (harrypierson@hotmail.com) Type: Standard - Status: Final - Created: 2019-09-02 + Status: + Version 1: Accepted + Version 2: Draft + Created: 2019-03-01 == Abstract == -This NEP describes the debug information format used by the +This NEP describes version two of the debug information format used by the [https://github.com/neo-project/neo-debugger Neo Smart Contract Debugger]. This information is generated by smart contract compilers such as [https://github.com/neo-project/neo-devpack-dotnet NCCS] @@ -22,11 +24,248 @@ about parameters, variables and storage items that exists in the contract source needed by the NeoVM and is discarded during contract compilation. The debugger also needs to source map information in order to map binary addresses in compiled contracts to locations in source code. +=== Version 2 Motivation === + +About six months after Neo N3 MainNet shipped, the debugger shipped a preview feature called +[https://github.com/neo-project/neo-debugger/blob/master/docs/storage-schema-overview.md Storage Schema]. +Storage Schema improves the developer experience by automatically decoding the contents of contract +storage keys and items. + +The debugger needs type information about contract storage in order to decode storage keys and items. +For the initial preview release, this type information lived in a separate JSON file written by hand. +Obviously, forcing the developer to maintain a separate file of type information is less than ideal. +NCCS was upgraded to emit storage schema information automatically from source code. + +As part of this work, a model for storage type information was created. While the runtime types +were limited to type information that can be encoded as a +[https://github.com/neo-project/neo/blob/master/src/neo/SmartContract/ContractParameterType.cs ContractParameterType], +the storage type model could encode additional type information such as the fields of a structure, +the type of a homogeneous collection or the key and value types of a map. + +It turned out to be trivial to extend the storage type information model to also support runtime +types. Futhermore, it turned out to be straightforward to generate this additional type information +for runtime types during compilation in the NCCS compiler. As such, the type information model was +renamed as the "contract type information model" and the NCCS compiler was further updated to generate +this unified type information for both runtime and storage types. + +While maintaining mostly the same structure, the string encoding of this new type model forces version +2 of the debug info format to break backwards compatibility with version 1. As such, the updated format +includes a '''version''' property so that the debugger can correctly interpret string encoded type information. +Of course, the debugger supports both v1 and v2 debug information, enabling programming language teams +to move to the new format in a time frame of their own choosing. There are no plans to remove support +for v1 debug information, so programming language teams don't have to update their compilers at all +if they so choose. + +
+Note, generating richer contract type model in NCCS is straightforward in part because of the rich type +information available in C#. Supporting some aspects of the new contract type model may be more difficult +or impossible in Neo compilers for dynamic languages such as Python. The v2 format has been designed +with such language limitations in mind. However, the contract type model is expected to evolve based +on feedback from Neo compiler teams as they upgrade their compilers to enable the new debugger functionality. +
+ == Rationale == -This format has been implemented by the Neo Smart Contract Debugger and multiple Neo smart contract +Version 1 of this format has been implemented by the Neo Smart Contract Debugger and multiple Neo smart contract compilers including NCCS, NEON, neo-boa, Neow3j and neo-go. +Version 2 of this format enables an improved variable inspection experience and supports unified type information +for both runtime and storage items. + +== NeoVM Item Type Model == + +Generally, type information is used to decode NeoVM types during debugging. For example, +NeoVM has no native string type - strings are represented in NeoVM as a +[https://github.com/neo-project/neo-vm/blob/master/src/neo-vm/Types/ByteString.cs ByteString]. +There is no way to tell that a given ByteString represents a string or not. However, with type +information about a runtime or storage type available from the debug info file, the debugger can +tell if a ByteString actually represents some higher order type such as a string, and address +or even a serialized compound type. + +The primary difference between v1 and v2 of the debug info format is the way type information is encoded. +Version 1 uses the existing [https://github.com/neo-project/neo/blob/master/src/neo/SmartContract/ContractParameterType.cs ContractParameterType enum type] +while Version 2 defines a type hierarchy (with string encoding) to represent additional type +information that would be impossible to encode with ContractParameterType. + +=== ContractType Type Model (Version 2) === + +This section describes both the abstract ContractType model as well as the concrete syntax used to +string encoding ContractTypes. + +Note, because the ContractType model namespace is unbounded (i.e. contract developers can define +their own named structs), built-in ContractTypes use a '''#''' prefix when serialized. This eliminates +the possibility of a name collision since '''#''' is not a supported identifier character in most +programming languages. + +The Version 2 type model includes six concrete ContractTypes. + +* Unspecified: Represents missing or unknown contract type information. +* Primitive: Represents contract type that stored in a NeoVM primitive type +* Interop: Represents a NeoVM InteropInterface object +* Struct: Represents a named, heterogenous collection of typed fields +* Array: Represents a homogenous collection of typed objects +* Map: Represents a typed mapping of key type to value type + +==== Unspecified ContractType ==== + +This is a contract type for which there is no further information available. Type information may be +unspecified because the compiler did not generate it or because of baseline validation done by the +debugger. For example, if the debug info claims a given variable should be an Array, but the +associated NeoVM stack item is *not* an array, the debugger will automatically substitute Unspecified +as the ContractType. + +Unspecified ContractType is serialized as the string '''#Unspecified'''. + +==== Primitive ContractType ==== + +This is a contract type that can be represented by a NeoVM PrimitiveType (Boolean, Integer or ByteString). +These types are serialized as byte arrays directly without the encoding needed by composite types. +There are nine primitive types: + +* Boolean +* Integer +* ByteArray +* String +* Hash160 +* Hash256 +* PublicKey +* Signature +* Address + +A primitive ContractType is serialized as it's name prefixed with the '''#'''. So a String primitive is +serialized as '''#String''' + +There is significant overlap between this list and the list of '''ContractParameterType'''s used in v1. +Notable changes are: + +* ContractParameterType.Any is represented as Unspecified as described above +* Only includes types represented in NeoVM as a PrimitiveType instance. This removes '''ContractParameterType''' values '''Array''', '''Map''' and '''InteropInterface'''. These non-primitive types are represented as explicit ContractType subclasses and are described below. +* Void is not a valid type in NeoVM, except as method return type. As such it is purposefully excluded from the ContractType model. Methods may specify '''#Void''' as their return type as described below +* Address has been added to the list - there was no '''Address''' type in '''ContractParameterType'''. Like '''Hash160''', '''Address''' is a ByteString 20 bytes long. However, where '''Hash160''' values are typically displayed by the debugger as a hex string, '''Address''' values are displayed as Neo N3 standard address strings, such as '''NaTtKdE8nt1E9FKKhH6hScXmDGPjgjpdhi'''. + +==== Interop ContractType ==== + +This is a ContractType that represents a NeoVM InteropInterface type. InteropInterface are opaque at +runtime - there is no way to query an InteropInterface instance for the .NET type that it wraps. However, +such information is typically available at compile time, so instead of simply rendering an opaque Interop +type in the debugger, the debug info can contain the name of the .NET type that the InteropInterface wraps. + +An interop contract type is serialized as '''#Interop<{wrapped-type-name}>''' with the name of the wrapped +type inside the angle brackets. + +
+Note, only the core Neo platform can define InteropInterface instances. As such, contract developers can +never generate an InteropContractType unless provided by the platform. +
+ +==== Struct ContractType ==== + +This is a ContractType that represents a heterogeneous collection of fields. It is represented in the NeoVM +as an Array or Struct type. NeoVM Struct inherits from NeoVM Array and their use in deployed contracts can be +inconsistent. As such, the debugger ignores NeoVM structs and simply interacts with Array. + +When displaying a Struct ContractType, the debugger validates that the associated NeoVM type is an array and +that the array length matches the struct field count. If this validation fails, the NeoVM item is displayed +as if the debug information was Unspecified. + +Each field of a struct has a name and a type. Any type may be specified as a field type. This implies structs +can create a hierarchy - for example a Person struct could contain a Name field, which in turn has FirstName +and LastName fields. + +Structs have a developer-specified name and which can be used to extend the global namespace of types. To avoid +name collisions, built-in ContractType have a '''#''' in their serialized format. As such, Structs may not have a '''#''' +in them. Additionally, user specified generic are not supported so structs may not have '''<''' or '''>''' in their names. +This applies to both the namespace and name segments of a struct's MemberName. + +There are a collection of built in structs provided by the Neo platform such as Block and Transaction. Definitions +of these structs are provided by the debugger and they live in the namespace '''#Neo'''. + +Structs are serialized as the MemberName namespace and name, separated by a period. So the built in Block type +is serialized as '''#Neo.Block''' where a user defined type would be something like '''Some.Namespace.TheTypeName'''. + +
+Note, while serialized MemberNames separate namespace from name with a comma, serialized ContractTypes are +used in comma separated strings, so the comma has to be replaced with some other character. At this time, +there is no forseen need to separate a struct name from its namespace at all. If there was such a need, using +the segment of the name following the final period seems reasonable. However, if a need arises, some other +non-comma, non-period character may be used to separate struct namespace from name. +
+ +==== Array ContractType ==== + +This contract type represents a homogenous collection of items. It is represented in the NeoVM by the Array +type. + +An Array ContractType has a single type argument, specify the type contained within the array. If the types +of the items in the array may not be consistent, Unspecified can be specified as the type argument. + +Array ContractType is serialized as '''#Array<{array item ContractType}>'''. If the array item type is omitted +(i.e. '''#Array<>'''), Unspecified is used as the default. Arrays may contain any other ContractType, including +other arrays (i.e. '''#Array<#Array<#String>>''' is allowed). + +==== Map ContractType ==== + +This contract type represents a mapping of primitive key to a ContractType value. It is represented in the +NeoVM by the Map type. + +A Map ContractType has two type arguments, specifying the type of the key and the value in the map array. +The key type of a Map *MUST* be a primitive type (described above). There are no restrictions on the Map +value type. Maps of Maps (i.e. '''#Map<#Integer:#Map<#String,#Address>>''') are allowed. + +Maps are serialized as '''#Map<{key type}:{value type}>'''. Note, the colon character is used to separate type +arguments since comma are used as a separator elsewhere. If the map type arguments are omitted (i.e. '''#Map<>'''), +'''#Map<#ByteArray,#Unspecified>''' is used as the default. + +=== ContractParameterType Model (Version 1) === + +EncodedTypes in v1 Neo debug info are string encoded values of the +[https://github.com/neo-project/neo/blob/master/src/neo/SmartContract/ContractParameterType.cs ContractParameterType enum type] + +* Any +* Boolean +* Integer +* ByteArray +* String +* Hash160 +* Hash256 +* PublicKey +* Signature +* Array +* Map +* InteropInterface +* Void + +The Any ContractParameterType acts like missing or unknown type information. Only information about +item in question available from the runtime will be used to decode. + +
+Note, the Void ContractParameterType value is only permitted for use as method return values. +
+ +==== Mapping ContractParameterType to ContractType ==== + +While the updated debugger supports both v1 and v2 debug information files, internally it maps +the limited set of ContractParameterTypes to a specific ContractType. + +For the ContractParameterTypes values that overlap with Primitive ContractTypes, the mapping is +one to one. For example. '''ContractParameterTypes.Hash160''' maps to '''PrimitiveContractType.Hash160''' +(encoded as '''#Hash160'''). + +'''ContractParameterTypes.Any''' maps to the Unspecified ContractType (i.e. '''#Unspecified'''). + +'''ContractParameterTypes.Array''' maps to an Array ContractType with an unspecified array type argument +(i.e. '''#Array<#Unspecified>'''). + +'''ContractParameterTypes.Map''' maps to an Map ContractType with a ByteArray key type argument and an +unspecified value type argument (i.e. '''#Map<#ByteArray:#Unspecified>'''). + +'''ContractParameterTypes.InteropInterface''' maps to an interop Contract Type where the wrapped +type name is missing (i.e. '''#Interop<>'''). + +As previously explained, '''ContractParameterTypes.Void''' does not map to a Contract Type. For method +return types that have '''ContractParameterTypes.Void''', this is mapped to the void return string '#Void'. +Otherwise, attempting to map '''ContractParameterTypes.Void''' to a Contract Type fails. + == Debug Info Format Specification == Neo compilers SHOULD emit debug information as part of the compilation process along with the required @@ -48,72 +287,79 @@ The full specification of this format is specified in "[[nep-19/neo-debug-info.s The debug info has the following structure. Note, for space optimization, several string properties contain multiple pieces of information encoded as a string. Those encodings are indicated in comments in the code below. - type TypeName = string; // format: ContractParamterType enum value - - type MemberName = string // format: "{namespace},{display-name} - - type Variable = string; // format: "{name},{TypeName}(,{slotIndex})? +
+type EncodedType = string; // format: For v1, this is a ContractParamterType enum value
+                           //         For v2, this is a string encoded ContractType. Details below
+type MemberName = string   // format: "{namespace},{display-name}
+type Variable = string;    // format: "{name},{EncodedType}(,{slotIndex})?
 
-  interface Method {
-    id: string;
+interface Method {
+    id?: string; // id field no longer needed, may be omitted in v2
     name: MemberName; 
     range: string; // format: "{start-address}-{end-address}
     params?: Variable[]; 
-    return?: TypeName;
+    return?: EncodedType | "#Void"; // #Void only allowed in v2
     variables?: Variable[]; 
     "sequence-points"?: string[]; // format: "{address}[{document-index}]{start-line}:{start-column}-{end-line}:{end-column}"
-  }
+}
 
-  interface Event {
-    id: string;
+interface Event {
+    id?: string; // id field no longer needed, may be omitted in v2
     name: MemberName; 
     params?: Variable[]; 
-  }
+}
 
-  interface DebugInformation {
+// top level debug info properties from v1 of the specification
+interface DebugInformation {
     hash: string; // hex-encoded UInt160
     documents?: string[]; // file paths
     events?: Event[];
     methods?: Method[];
     "static-variables"?: Variable[]; 
-  }
+}
+
+// Structs only supported in v2
+interface Struct {
+    name: MemberName;
+    fields?: string[]; // format: "{name},{string encoded ContractType}"
+}
+
+// StorageGroups only supported in v2
+interface StorageGroup {
+    name: MemberName;
+    type: EncodedType; // Must be string encoded ContractType
+    prefix: string; // format: hex-encoded byte array
+    segments?: string[]; // format: "{name},{string encoded ContractType}"
+}
+
+// top level debug info properties added in v2 of the specification
+interface DebugInfoV2 : DebugInformation {
+    version: number;
+    checksum: number;
+    structs?: Struct[];
+    storages?: StorageGroup[];
+}
+
-=== TypeName === +=== EncodedType === -TypeNames in Neo debug info are string encoded values from the -[https://github.com/neo-project/neo/blob/master/src/neo/SmartContract/ContractParameterType.cs ContractParameterType enum type] - -* Any -* Boolean -* Integer -* ByteArray -* String -* Hash160 -* Hash256 -* PublicKey -* Signature -* Array -* Map -* InteropInterface -* Void +EncodedType is simply string encoded type information. Details are above in the Type Model section. -Generally, this type information is used to decode NeoVM types during debugging. For example, NeoVM has no -native string type - strings are represented in NeoVM as a [https://github.com/neo-project/neo-vm/blob/master/src/neo-vm/Types/ByteString.cs ByteString]. -The additional type information enables the debugger to treat the bytes in the NeoVM ByteString as a UTF-8 -encoded string in order to decode the string for the developer. +Note, ''*ALL*'' EncodedTypes in a v1 debug info file ''*MUST*'' be ContractParameterType values while ''*ALL*'' EncodedTypes +in a v2 debug info file ''*MUST*'' be string encoded ContractTypes. === Variable === Variable types are used to encode name and type information about NeoVM arguments, local variables and static fields. Additionally, a variable may include an optional slot index. This is useful for scenarios where the compiler may use slots for hidden variables not authored by the developer. If the slot index is not specified, -the array index of the Variable type is used as the slot index. For a given variable array, ''ALL'' variables ''MUST'' -include a slot index if ''ANY'' variables contain a slot index. Mixing variables with and and without an optional -slot index in a single Variable array is '''NOT SUPPORTED'''. It is supported to have some Variable arrays include +the array index of the Variable type is used as the slot index. For a given variable array, *ALL* variables *MUST* +include a slot index if *ANY* variables contain a slot index. Mixing variables with and and without an optional +slot index in a single Variable array is *NOT SUPPORTED*. It is supported to have some Variable arrays include slot index information while other Variable arrays in the same debug info file do not. Name, type and optional slot index are combined into a single comma separated string. A Variable without slot -index has a single comma (i.e. "varName,varType") while a Variable with index has two commas (i.e. "varName,varType,1"). +index has a single comma (i.e. '''varName,varType''') while a Variable with index has two commas (i.e. '''varName,varType,1'''). === MemberName === @@ -125,7 +371,6 @@ MemberName string MUST start with a comma (i.e. ",SomeName"). Method types have the following fields: -* id: a unique string representing the method. * name: a MemberName with the method's name and optional namespace * range: the range of NeoVM bytecode addresses that is associated with this method. Range is encoded as a string with the start and end addresses as integers separated by a dash * params: a collection of Variable instances representing the NeoVM arguments associated with this method @@ -133,6 +378,13 @@ Method types have the following fields: * variables: a collection of Variable instances representing the NeoVM local variables associated with this method * sequence-points: a collection of strings that encode a map of NeoVM bytecode addresses back to source code locations. +While the v1 ContractParameterType model has a '''Void''' value, the v2 ContractType model purposefully +lacks a mechanism to encode the '''void''' type. While many programming languages do support a general +use '''void''' or '''unit''' type, Neo contracts only support '''void''' as a method return type. As such, void +return methods in a v2 debug info file may specify '''#Void''' as their '''return''' property value, even +though that is not a legal encoded ContractType as described above. '''#Void''' cannot be specified +for any other EncodedType except method '''return''' properties in a v2 debug info file. + Note, params, return, variables and sequence-points are all optional. A Method object with no return property will default to having Void return type. A Method object with no params, variables or sequence-points properties will default to having an empty array of the collection in question. @@ -154,23 +406,71 @@ The six integers of a single sequence point are string encoded using this patter Event types have the following fields: -* id: a unique string representing the method. * name: a MemberName with the method's name and optional namespace * params: a collection of Variable instances representing the NeoVM arguments associated with this event Note, like Method types, params is optional. An event object with no params property will default to an empty params array. +=== Struct === + +Struct types have the following properties + +* name: a MemberName with the struct's name and optional namespace +* fields: a collection of strings containing each field's name and string encoded ContractType. Basically the same as a Variable without any slot index info. + +Because Structs are a v2 feature, the field type MUST be a string encoded ContractType rather +than a ContractParameterType. + +Note, fields is optional. A struct object with no fields property will default to an +empty fields array. + +=== StorageGroup === + +StorageGroup types have the following properties + +* name: a MemberName with the storage group's name and optional namespace +* type: the string encoded ContractType +* prefix: a hex-encoded byte array of the hard coded prefix for all keys in this group +* segments: a collection of strings containing each fields name and string encoded ContractType. Similar to a Variable without slot index info, except that the ContractType must be a primitive type. + +Because StorageGroups are a v2 feature, the storage group type and each segment type MUST be a string +encoded ContractType. Furthermore, segment types SHOULD be *PRIMITIVE* Contract Types and each segment +except for the last segment SHOULD be a fixed size (Address, Hash160, Hash256, PublicKey and Signature). +The debugger does not support non primitive keys or variable-length segments that precede other segments. +In those cases, the debugger will simply default to a single key segment with primitive ByteArray type. + +Note, segments is optional. A StorageGroup object with no segments property will default to an +empty segments array. + === DebugInformation === Top level debug information has the following fields +==== version ==== + +
+Note, this property was added in v2 +
+ +This property stores an integer representing the version of the format a given debug info file is using. +This value MUST be `1` or `2`. If omitted, this property defaults to version `1`. + ==== hash ==== This property stores the UInt160 hash value of the contract's Script. Note, this is '''NOT''' the same as a deployed contract's script hash. The debugger uses this hash value to map deployed contracts to their debug information. The hash value is stored as a hex encoded string with an optional "0x" prefix. +==== `checksum` ==== + +
+Note, this property was added in v2. +
+ +This property stores the contract's NEF file checksum value. This field is required for version 2 and +later debug info documents. + ==== documents ==== This property stores an array of file paths, used in sequence point data. These paths should be full file @@ -196,8 +496,35 @@ This property stores an array of Event types as described above. Each Event obje of a contract notification that may be fired during contract execution. If omitted, this property defaults to an empty array. +==== structs ==== + +
+Note, this property was added in v2 +
+ +This property stores an array of Struct types as described above. Each Struct object represents a +heterogeneous collection of named fields, each with a specified type. These structs may be used both +runtime NeoVM types as well as serialized storage types. If omitted, this property defaults to an +empty array. + +==== storageGroups ==== + +
+Note, this property was added in v2 +
+ +This property stores an array of StorageGroup types as described above. Each StorageGroup object +represents a prefixed collection of one or more storage key/items. These storageGroups are used +to decode contract storage for the debugger. If omitted, this property defaults to an empty array. + == Backwards Compatibility == +
+Note, as described above, type encoding for v2 debug information is not backwards compatible +with v1 debug information. This section describes backwards compatibility with Neo debug +formats prior to the v1 version of this NEP. +
+ Initial preview releases of the Neo Smart Contract Debugger for Neo Legacy used a more verbose format for debug info. That format was incompatible with the format described in this document, but never shipped a production release. Production releases of the Neo Legacy debugger use a @@ -212,4 +539,5 @@ Details regarding older versions of the debug info format is available in the == Implementation == -NCCS: https://github.com/neo-project/neo-devpack-dotnet/blob/e9b00b7284819699a522c2d94ec22ef1d5e5be8a/src/Neo.Compiler.CSharp/CompilationContext.cs#L330-L362 +* Version 1: https://github.com/neo-project/neo-devpack-dotnet/blob/master/src/Neo.Compiler.CSharp/CompilationContext.cs#L330 +* Version 2 (preview): https://github.com/ngdenterprise/neo-devpack-dotnet/blob/storage-schema-preview/src/Neo.Compiler.CSharp/CompilationContext.cs#L592 From 7ef78e595c7a67db71744acbd10f73803b09ae6d Mon Sep 17 00:00:00 2001 From: Harry Pierson Date: Thu, 1 Dec 2022 16:12:10 -0800 Subject: [PATCH 2/2] add #iterator --- nep-19.mediawiki | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/nep-19.mediawiki b/nep-19.mediawiki index 3f24d046..1c4b27ca 100644 --- a/nep-19.mediawiki +++ b/nep-19.mediawiki @@ -105,6 +105,7 @@ The Version 2 type model includes six concrete ContractTypes. * Struct: Represents a named, heterogenous collection of typed fields * Array: Represents a homogenous collection of typed objects * Map: Represents a typed mapping of key type to value type +* Iterator: Represents a collection traversal type ==== Unspecified ContractType ==== @@ -184,7 +185,7 @@ Structs are serialized as the MemberName namespace and name, separated by a peri is serialized as '''#Neo.Block''' where a user defined type would be something like '''Some.Namespace.TheTypeName'''.
-Note, while serialized MemberNames separate namespace from name with a comma, serialized ContractTypes are +Note,https://github.com/neo-project/neo-devpack-dotnet/pull/770ized MemberNames separate namespace from name with a comma, serialized ContractTypes are used in comma separated strings, so the comma has to be replaced with some other character. At this time, there is no forseen need to separate a struct name from its namespace at all. If there was such a need, using the segment of the name following the final period seems reasonable. However, if a need arises, some other @@ -216,6 +217,27 @@ Maps are serialized as '''#Map<{key type}:{value type}>'''. Note, the colon char arguments since comma are used as a separator elsewhere. If the map type arguments are omitted (i.e. '''#Map<>'''), '''#Map<#ByteArray,#Unspecified>''' is used as the default. +==== Iterator ContractType ==== + +This contract type represents a type for traversing a homogenous collection of items. It is represented in Neo +by the Iterator type. Neo iterators have two methods: '''Next''' which is used to traverse the container (returning +a boolean to indicate if there are more elements in the collection) and '''Value''' whcih returns the current +value in the collection being iterated. + +An Iterator ContractType has a single type argument, specify the type contained within the array. If the types +of the items in the collection being iterated may not be consistent, Unspecified can be specified as the type argument. + +Iterator ContractType is serialized as '''#Iterator<{collection item ContractType}>'''. If the iterator +item type is omitted (i.e. '''#Iterator<>'''), Unspecified is used as the default. Iterators may contain +any other ContractType, including other iterators (i.e. '''#Iterator<#Iterator<#String>>''' is allowed). + +Note, Neo Iterators are primarily used to traverse contract storage. Storage iterators can iterate over storage keys, +storage values or key/value pairs. When traversing storage key/value pairs, the return type is a struct containing both +the key and its assoicated value. There is no built in type to represent a key/value pair. If the developer specifies +they are traversing the key/value pairs in contract storage, the associated compiler needs to emit the struct +definition for the key/value pairs being traversed. + + === ContractParameterType Model (Version 1) === EncodedTypes in v1 Neo debug info are string encoded values of the