2020-03-18 15:21:12 +00:00
|
|
|
package manifest
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
|
2020-06-09 09:12:56 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
2020-03-18 15:21:12 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
|
|
|
)
|
|
|
|
|
|
|
|
// MaxManifestSize is a max length for a valid contract manifest.
|
|
|
|
const MaxManifestSize = 2048
|
|
|
|
|
|
|
|
// ABI represents a contract application binary interface.
|
|
|
|
type ABI struct {
|
|
|
|
Hash util.Uint160 `json:"hash"`
|
|
|
|
EntryPoint Method `json:"entryPoint"`
|
|
|
|
Methods []Method `json:"methods"`
|
|
|
|
Events []Event `json:"events"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// Manifest represens contract metadata.
|
|
|
|
type Manifest struct {
|
|
|
|
// ABI is a contract's ABI.
|
|
|
|
ABI ABI
|
|
|
|
// Groups is a set of groups to which a contract belongs.
|
|
|
|
Groups []Group
|
|
|
|
// Features is a set of contract's features.
|
|
|
|
Features smartcontract.PropertyState
|
|
|
|
Permissions []Permission
|
|
|
|
// Trusts is a set of hashes to a which contract trusts.
|
|
|
|
Trusts WildUint160s
|
|
|
|
// SafeMethods is a set of names of safe methods.
|
|
|
|
SafeMethods WildStrings
|
|
|
|
// Extra is an implementation-defined user data.
|
|
|
|
Extra interface{}
|
|
|
|
}
|
|
|
|
|
|
|
|
type manifestAux struct {
|
|
|
|
ABI *ABI `json:"abi"`
|
|
|
|
Groups []Group `json:"groups"`
|
|
|
|
Features map[string]bool `json:"features"`
|
|
|
|
Permissions []Permission `json:"permissions"`
|
|
|
|
Trusts *WildUint160s `json:"trusts"`
|
2020-07-09 13:29:56 +00:00
|
|
|
SafeMethods *WildStrings `json:"safemethods"`
|
2020-03-18 15:21:12 +00:00
|
|
|
Extra interface{} `json:"extra"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewManifest returns new manifest with necessary fields initialized.
|
|
|
|
func NewManifest(h util.Uint160) *Manifest {
|
|
|
|
m := &Manifest{
|
|
|
|
ABI: ABI{
|
|
|
|
Hash: h,
|
|
|
|
Methods: []Method{},
|
|
|
|
Events: []Event{},
|
|
|
|
},
|
|
|
|
Groups: []Group{},
|
|
|
|
Features: smartcontract.NoProperties,
|
|
|
|
}
|
|
|
|
m.Trusts.Restrict()
|
|
|
|
m.SafeMethods.Restrict()
|
|
|
|
return m
|
|
|
|
}
|
|
|
|
|
|
|
|
// DefaultManifest returns default contract manifest.
|
|
|
|
func DefaultManifest(h util.Uint160) *Manifest {
|
|
|
|
m := NewManifest(h)
|
|
|
|
m.ABI.EntryPoint = *DefaultEntryPoint()
|
|
|
|
m.Permissions = []Permission{*NewPermission(PermissionWildcard)}
|
|
|
|
return m
|
|
|
|
}
|
|
|
|
|
|
|
|
// CanCall returns true is current contract is allowed to call
|
|
|
|
// method of another contract.
|
|
|
|
func (m *Manifest) CanCall(toCall *Manifest, method string) bool {
|
|
|
|
// this if is not present in the original code but should probably be here
|
|
|
|
if toCall.SafeMethods.Contains(method) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
for i := range m.Permissions {
|
|
|
|
if m.Permissions[i].IsAllowed(toCall, method) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2020-07-15 11:39:20 +00:00
|
|
|
// IsValid checks whether the given hash is the one specified in manifest and
|
|
|
|
// verifies it against all the keys in manifest groups.
|
|
|
|
func (m *Manifest) IsValid(hash util.Uint160) bool {
|
|
|
|
if m.ABI.Hash != hash {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
for _, g := range m.Groups {
|
|
|
|
if !g.IsValid(hash) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2020-03-18 15:21:12 +00:00
|
|
|
// MarshalJSON implements json.Marshaler interface.
|
|
|
|
func (m *Manifest) MarshalJSON() ([]byte, error) {
|
|
|
|
features := make(map[string]bool)
|
|
|
|
features["storage"] = m.Features&smartcontract.HasStorage != 0
|
|
|
|
features["payable"] = m.Features&smartcontract.IsPayable != 0
|
|
|
|
aux := &manifestAux{
|
|
|
|
ABI: &m.ABI,
|
|
|
|
Groups: m.Groups,
|
|
|
|
Features: features,
|
|
|
|
Permissions: m.Permissions,
|
|
|
|
Trusts: &m.Trusts,
|
|
|
|
SafeMethods: &m.SafeMethods,
|
|
|
|
Extra: m.Extra,
|
|
|
|
}
|
|
|
|
return json.Marshal(aux)
|
|
|
|
}
|
|
|
|
|
|
|
|
// UnmarshalJSON implements json.Unmarshaler interface.
|
|
|
|
func (m *Manifest) UnmarshalJSON(data []byte) error {
|
|
|
|
aux := &manifestAux{
|
|
|
|
ABI: &m.ABI,
|
|
|
|
Trusts: &m.Trusts,
|
|
|
|
SafeMethods: &m.SafeMethods,
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := json.Unmarshal(data, aux); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if aux.Features["storage"] {
|
|
|
|
m.Features |= smartcontract.HasStorage
|
|
|
|
}
|
|
|
|
if aux.Features["payable"] {
|
|
|
|
m.Features |= smartcontract.IsPayable
|
|
|
|
}
|
|
|
|
|
|
|
|
m.Groups = aux.Groups
|
|
|
|
m.Permissions = aux.Permissions
|
|
|
|
m.Extra = aux.Extra
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2020-06-09 09:12:56 +00:00
|
|
|
|
|
|
|
// EncodeBinary implements io.Serializable.
|
|
|
|
func (m *Manifest) EncodeBinary(w *io.BinWriter) {
|
|
|
|
data, err := json.Marshal(m)
|
|
|
|
if err != nil {
|
|
|
|
w.Err = err
|
|
|
|
return
|
|
|
|
}
|
|
|
|
w.WriteVarBytes(data)
|
|
|
|
}
|
|
|
|
|
|
|
|
// DecodeBinary implements io.Serializable.
|
|
|
|
func (m *Manifest) DecodeBinary(r *io.BinReader) {
|
|
|
|
data := r.ReadVarBytes()
|
|
|
|
if r.Err != nil {
|
|
|
|
return
|
|
|
|
} else if err := json.Unmarshal(data, m); err != nil {
|
|
|
|
r.Err = err
|
|
|
|
}
|
|
|
|
}
|