Contract Class Structure
Restrictions for Simplified Code Checks
Inheritance Rules
- Only one inheritance is allowed from
ContractBase
, generated by the contract plugin as a nested type inContractContainer
. - Only one inheritance is allowed from
CSharpSmartContract
. - Only one inheritance is allowed from
ContractState
. - The type inherited from
ContractState
should be the element type of theCSharpSmartContract
generic instance type.
If these rules are not followed, code deployment will fail.
Field Usage Limitations
In Contract Implementation Class
- Initial values for non-readonly, non-constant fields are not allowed (for both static and non-static fields). This is because their value will reset to 0 or null after the first execution, losing the initial value.
Allowed:
class MyContract : MyContractBase
{
int test;
static const int test = 2;
}
Not Allowed:
class MyContract : MyContractBase
{
! int test = 2;
}
class MyContract : MyContractBase
{
int test;
public MyContract
{
! test = 2;
}
}
- Only primitive types or the following types are allowed for readonly/constant fields:
Marshaller<T>
Method<T, T>
MessageParser<T>
FieldCodec<T>
MapField<T, T>
ReadonlyCollection<T>
ReadonlyDictionary<T, T>
Note: T can only be a primitive type.
In Non-Contract Classes (Classes not inheriting from ContractBase<T>
)
- Initial values for non-readonly, non-constant static fields are not allowed. They reset to 0 or null after the first execution, losing the initial value.
Allowed:
class AnyClass
{
static int test;
}
Not Allowed:
class AnyClass
{
! static int test = 2;
}
class AnyClass
{
static int test;
public AnyClass
{
! test = 2;
}
}
- Exception: Fields with FileDescriptor types are allowed due to protobuf-generated code. These fields don’t have a readonly modifier and write access to them is allowed only from the constructor of the declaring type.
Allowed:
public class TestType
{
private static FileDescriptor test;
public class TestType
{
test = ...
}
}
Not Allowed:
public class TestType
{
private static FileDescriptor test;
public TestType
{
test = ...
}
! public void SetFromSomeWhereElse(FileDescriptor input)
! {
! test = input;
! }
}
-
Accessing test fields is restricted to the declaring type’s constructor only.
-
Only the following types are allowed for readonly/constant static fields:
Marshaller<T>
Method<T, T>
MessageParser<T>
FieldCodec<T>
MapField<T, T>
ReadonlyCollection<T>
ReadonlyDictionary<T, T>
Note: T can only be a primitive type.
- Exception: If a type has a readonly field of the same type as itself, it is only allowed if the type has no instance fields (to support LINQ-related generated types).
Allowed:
public class TestType
{
private static readonly TestType test;
private static int i;
}
Not Allowed:
public class TestType
{
private static readonly TestType test;
! private int i;
}
In Contract State
In contract state, only the following types are allowed:
Primitive Types
BoolState
Int32State
UInt32State
Int64State
UInt64State
StringState
BytesState
Complex Types
Complex Types
SingletonState<T>
ReadonlyState<T>
MappedState<T, T>
MappedState<T, T, T>
MappedState<T, T, T, T>
MappedState<T, T, T, T, T>
MethodReference<T, T>
ProtobufState<T>
ContractReferenceState