Skip to content

Commit

Permalink
Validate contract updates (#593)
Browse files Browse the repository at this point in the history
* Add equal method to the ast.Type

* Validate contracts before update

* Validate contracts before update

* Introduce a visitor for AST type equality checking

* Add tests

* Sync with the latest changes

* Refactor code. Introduce dedicated errors for update validation errors

* Get the old AST from the host enviornment, if available

* Add enum validation

* Fix field validation

* Refactor code

* Improve non-storable-type error
  • Loading branch information
SupunS authored Feb 17, 2021
1 parent c59970f commit 37fad8c
Show file tree
Hide file tree
Showing 15 changed files with 1,573 additions and 3 deletions.
12 changes: 12 additions & 0 deletions runtime/ast/composite.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ func (d *CompositeDeclaration) DeclarationAccess() Access {
return d.Access
}

func (d *CompositeDeclaration) DeclarationMembers() *Members {
return d.Members
}

func (d *CompositeDeclaration) MarshalJSON() ([]byte, error) {
type Alias CompositeDeclaration
return json.Marshal(&struct {
Expand Down Expand Up @@ -101,6 +105,10 @@ func (d *FieldDeclaration) DeclarationAccess() Access {
return d.Access
}

func (d *FieldDeclaration) DeclarationMembers() *Members {
return nil
}

func (d *FieldDeclaration) MarshalJSON() ([]byte, error) {
type Alias FieldDeclaration
return json.Marshal(&struct {
Expand Down Expand Up @@ -147,6 +155,10 @@ func (d *EnumCaseDeclaration) EndPosition() Position {
return d.Identifier.EndPosition()
}

func (d *EnumCaseDeclaration) DeclarationMembers() *Members {
return nil
}

func (d *EnumCaseDeclaration) MarshalJSON() ([]byte, error) {
type Alias EnumCaseDeclaration
return json.Marshal(&struct {
Expand Down
1 change: 1 addition & 0 deletions runtime/ast/declaration.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,5 @@ type Declaration interface {
DeclarationIdentifier() *Identifier
DeclarationKind() common.DeclarationKind
DeclarationAccess() Access
DeclarationMembers() *Members
}
8 changes: 8 additions & 0 deletions runtime/ast/function_declaration.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ func (d *FunctionDeclaration) ToExpression() *FunctionExpression {
}
}

func (d *FunctionDeclaration) DeclarationMembers() *Members {
return nil
}

func (d *FunctionDeclaration) MarshalJSON() ([]byte, error) {
type Alias FunctionDeclaration
return json.Marshal(&struct {
Expand Down Expand Up @@ -123,6 +127,10 @@ func (d *SpecialFunctionDeclaration) DeclarationAccess() Access {
return d.FunctionDeclaration.DeclarationAccess()
}

func (d *SpecialFunctionDeclaration) DeclarationMembers() *Members {
return nil
}

func (d *SpecialFunctionDeclaration) MarshalJSON() ([]byte, error) {
type Alias SpecialFunctionDeclaration
return json.Marshal(&struct {
Expand Down
4 changes: 4 additions & 0 deletions runtime/ast/import.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ func (d *ImportDeclaration) DeclarationAccess() Access {
return AccessNotSpecified
}

func (d *ImportDeclaration) DeclarationMembers() *Members {
return nil
}

func (d *ImportDeclaration) MarshalJSON() ([]byte, error) {
type Alias ImportDeclaration
return json.Marshal(&struct {
Expand Down
4 changes: 4 additions & 0 deletions runtime/ast/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ func (d *InterfaceDeclaration) DeclarationKind() common.DeclarationKind {
return d.CompositeKind.DeclarationKind(true)
}

func (d *InterfaceDeclaration) DeclarationMembers() *Members {
return d.Members
}

func (d *InterfaceDeclaration) MarshalJSON() ([]byte, error) {
type Alias InterfaceDeclaration
return json.Marshal(&struct {
Expand Down
22 changes: 21 additions & 1 deletion runtime/ast/memberindices.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ type memberIndices struct {
_functions []*FunctionDeclaration
// Use `FunctionsByIdentifier()` instead
_functionsByIdentifier map[string]*FunctionDeclaration
// Use `CompositesByIdentifier()` instead
_compositesByIdentifier map[string]*CompositeDeclaration
// Use `InterfacesByIdentifier()` instead
_interfacesByIdentifier map[string]*InterfaceDeclaration
// Use `Interfaces()` instead
_interfaces []*InterfaceDeclaration
// Use `Composites()` instead
Expand All @@ -64,6 +68,16 @@ func (i *memberIndices) FunctionsByIdentifier(declarations []Declaration) map[st
return i._functionsByIdentifier
}

func (i *memberIndices) CompositesByIdentifier(declarations []Declaration) map[string]*CompositeDeclaration {
i.once.Do(i.initializer(declarations))
return i._compositesByIdentifier
}

func (i *memberIndices) InterfacesByIdentifier(declarations []Declaration) map[string]*InterfaceDeclaration {
i.once.Do(i.initializer(declarations))
return i._interfacesByIdentifier
}

func (i *memberIndices) Initializers(declarations []Declaration) []*SpecialFunctionDeclaration {
i.once.Do(i.initializer(declarations))
return i._initializers
Expand Down Expand Up @@ -123,8 +137,12 @@ func (i *memberIndices) init(declarations []Declaration) {
i._destructors = make([]*SpecialFunctionDeclaration, 0)
i._initializers = make([]*SpecialFunctionDeclaration, 0)

i._interfaces = make([]*InterfaceDeclaration, 0)
i._composites = make([]*CompositeDeclaration, 0)
i._compositesByIdentifier = make(map[string]*CompositeDeclaration)

i._interfaces = make([]*InterfaceDeclaration, 0)
i._interfacesByIdentifier = make(map[string]*InterfaceDeclaration)

i._enumCases = make([]*EnumCaseDeclaration, 0)

for _, declaration := range declarations {
Expand All @@ -149,9 +167,11 @@ func (i *memberIndices) init(declarations []Declaration) {

case *InterfaceDeclaration:
i._interfaces = append(i._interfaces, declaration)
i._interfacesByIdentifier[declaration.Identifier.Identifier] = declaration

case *CompositeDeclaration:
i._composites = append(i._composites, declaration)
i._compositesByIdentifier[declaration.Identifier.Identifier] = declaration

case *EnumCaseDeclaration:
i._enumCases = append(i._enumCases, declaration)
Expand Down
8 changes: 8 additions & 0 deletions runtime/ast/members.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,14 @@ func (m *Members) FunctionsByIdentifier() map[string]*FunctionDeclaration {
return m.indices.FunctionsByIdentifier(m.declarations)
}

func (m *Members) CompositesByIdentifier() map[string]*CompositeDeclaration {
return m.indices.CompositesByIdentifier(m.declarations)
}

func (m *Members) InterfacesByIdentifier() map[string]*InterfaceDeclaration {
return m.indices.InterfacesByIdentifier(m.declarations)
}

func (m *Members) Initializers() []*SpecialFunctionDeclaration {
return m.indices.Initializers(m.declarations)
}
Expand Down
4 changes: 4 additions & 0 deletions runtime/ast/pragma.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ func (d *PragmaDeclaration) DeclarationAccess() Access {
return AccessNotSpecified
}

func (d *PragmaDeclaration) DeclarationMembers() *Members {
return nil
}

func (d *PragmaDeclaration) MarshalJSON() ([]byte, error) {
type Alias PragmaDeclaration
return json.Marshal(&struct {
Expand Down
4 changes: 4 additions & 0 deletions runtime/ast/transaction_declaration.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ func (d *TransactionDeclaration) DeclarationAccess() Access {
return AccessNotSpecified
}

func (d *TransactionDeclaration) DeclarationMembers() *Members {
return nil
}

func (d *TransactionDeclaration) MarshalJSON() ([]byte, error) {
type Alias TransactionDeclaration
return json.Marshal(&struct {
Expand Down
53 changes: 53 additions & 0 deletions runtime/ast/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ type Type interface {
HasPosition
fmt.Stringer
isType()
CheckEqual(other Type, checker TypeEqualityChecker) error
}

// NominalType represents a named type
Expand Down Expand Up @@ -111,6 +112,14 @@ func (t *NominalType) MarshalJSON() ([]byte, error) {
})
}

func (t *NominalType) IsQualifiedName() bool {
return len(t.NestedIdentifiers) > 0
}

func (t *NominalType) CheckEqual(other Type, checker TypeEqualityChecker) error {
return checker.CheckNominalTypeEquality(t, other)
}

// OptionalType represents am optional variant of another type

type OptionalType struct {
Expand Down Expand Up @@ -145,6 +154,10 @@ func (t *OptionalType) MarshalJSON() ([]byte, error) {
})
}

func (t *OptionalType) CheckEqual(other Type, checker TypeEqualityChecker) error {
return checker.CheckOptionalTypeEquality(t, other)
}

// VariableSizedType is a variable sized array type

type VariableSizedType struct {
Expand All @@ -169,6 +182,10 @@ func (t *VariableSizedType) MarshalJSON() ([]byte, error) {
})
}

func (t *VariableSizedType) CheckEqual(other Type, checker TypeEqualityChecker) error {
return checker.CheckVariableSizedTypeEquality(t, other)
}

// ConstantSizedType is a constant sized array type

type ConstantSizedType struct {
Expand All @@ -194,6 +211,10 @@ func (t *ConstantSizedType) MarshalJSON() ([]byte, error) {
})
}

func (t *ConstantSizedType) CheckEqual(other Type, checker TypeEqualityChecker) error {
return checker.CheckConstantSizedTypeEquality(t, other)
}

// DictionaryType

type DictionaryType struct {
Expand All @@ -219,6 +240,10 @@ func (t *DictionaryType) MarshalJSON() ([]byte, error) {
})
}

func (t *DictionaryType) CheckEqual(other Type, checker TypeEqualityChecker) error {
return checker.CheckDictionaryTypeEquality(t, other)
}

// FunctionType

type FunctionType struct {
Expand Down Expand Up @@ -252,6 +277,10 @@ func (t *FunctionType) MarshalJSON() ([]byte, error) {
})
}

func (t *FunctionType) CheckEqual(other Type, checker TypeEqualityChecker) error {
return checker.CheckFunctionTypeEquality(t, other)
}

// ReferenceType

type ReferenceType struct {
Expand Down Expand Up @@ -293,6 +322,10 @@ func (t *ReferenceType) MarshalJSON() ([]byte, error) {
})
}

func (t *ReferenceType) CheckEqual(other Type, checker TypeEqualityChecker) error {
return checker.CheckReferenceTypeEquality(t, other)
}

// RestrictedType

type RestrictedType struct {
Expand Down Expand Up @@ -330,6 +363,10 @@ func (t *RestrictedType) MarshalJSON() ([]byte, error) {
})
}

func (t *RestrictedType) CheckEqual(other Type, checker TypeEqualityChecker) error {
return checker.CheckRestrictedTypeEquality(t, other)
}

// InstantiationType represents an instantiation of a generic (nominal) type

type InstantiationType struct {
Expand Down Expand Up @@ -375,3 +412,19 @@ func (t *InstantiationType) MarshalJSON() ([]byte, error) {
Alias: (*Alias)(t),
})
}

func (t *InstantiationType) CheckEqual(other Type, checker TypeEqualityChecker) error {
return checker.CheckInstantiationTypeEquality(t, other)
}

type TypeEqualityChecker interface {
CheckNominalTypeEquality(*NominalType, Type) error
CheckOptionalTypeEquality(*OptionalType, Type) error
CheckVariableSizedTypeEquality(*VariableSizedType, Type) error
CheckConstantSizedTypeEquality(*ConstantSizedType, Type) error
CheckDictionaryTypeEquality(*DictionaryType, Type) error
CheckFunctionTypeEquality(*FunctionType, Type) error
CheckReferenceTypeEquality(*ReferenceType, Type) error
CheckRestrictedTypeEquality(*RestrictedType, Type) error
CheckInstantiationTypeEquality(*InstantiationType, Type) error
}
4 changes: 4 additions & 0 deletions runtime/ast/variable_declaration.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@ func (d *VariableDeclaration) DeclarationAccess() Access {
return d.Access
}

func (d *VariableDeclaration) DeclarationMembers() *Members {
return nil
}

func (d *VariableDeclaration) MarshalJSON() ([]byte, error) {
type Alias VariableDeclaration
return json.Marshal(&struct {
Expand Down
Loading

0 comments on commit 37fad8c

Please sign in to comment.