Merge pull request #1597 from nspcc-dev/fix/safemethods
manifest: add `Safe` flag to method descriptor
This commit is contained in:
commit
02457d9f77
15 changed files with 82 additions and 85 deletions
|
@ -251,9 +251,6 @@ func _deploy(isUpdate bool) {}
|
|||
Trusts: manifest.WildUint160s{
|
||||
Value: []util.Uint160{},
|
||||
},
|
||||
SafeMethods: manifest.WildStrings{
|
||||
Value: []string{},
|
||||
},
|
||||
Extra: nil,
|
||||
}
|
||||
require.ElementsMatch(t, expected.ABI.Methods, actual.ABI.Methods)
|
||||
|
@ -261,7 +258,6 @@ func _deploy(isUpdate bool) {}
|
|||
require.Equal(t, expected.Groups, actual.Groups)
|
||||
require.Equal(t, expected.Permissions, actual.Permissions)
|
||||
require.Equal(t, expected.Trusts, actual.Trusts)
|
||||
require.Equal(t, expected.SafeMethods, actual.SafeMethods)
|
||||
require.Equal(t, expected.Extra, actual.Extra)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -120,13 +120,11 @@ func NewContractMD(name string) *ContractMD {
|
|||
}
|
||||
|
||||
// AddMethod adds new method to a native contract.
|
||||
func (c *ContractMD) AddMethod(md *MethodAndPrice, desc *manifest.Method, safe bool) {
|
||||
func (c *ContractMD) AddMethod(md *MethodAndPrice, desc *manifest.Method) {
|
||||
c.Manifest.ABI.Methods = append(c.Manifest.ABI.Methods, *desc)
|
||||
md.MD = desc
|
||||
desc.Safe = (md.RequiredFlags & smartcontract.AllowModifyStates) == 0
|
||||
c.Methods[desc.Name] = *md
|
||||
if safe {
|
||||
c.Manifest.SafeMethods.Add(desc.Name)
|
||||
}
|
||||
}
|
||||
|
||||
// AddEvent adds new event to a native contract.
|
||||
|
|
|
@ -46,8 +46,13 @@ func callExInternal(ic *interop.Context, h []byte, name string, args []stackitem
|
|||
if strings.HasPrefix(name, "_") {
|
||||
return errors.New("invalid method name (starts with '_')")
|
||||
}
|
||||
ctx := ic.VM.Context()
|
||||
if ctx != nil && ctx.IsDeployed() {
|
||||
md := cs.Manifest.ABI.GetMethod(name)
|
||||
if md == nil {
|
||||
return errors.New("method not found")
|
||||
}
|
||||
if md.Safe {
|
||||
f &^= smartcontract.AllowModifyStates
|
||||
} else if ctx := ic.VM.Context(); ctx != nil && ctx.IsDeployed() {
|
||||
curr, err := ic.DAO.GetContractState(ic.VM.GetCurrentScriptHash())
|
||||
if err == nil {
|
||||
if !curr.Manifest.CanCall(u, &cs.Manifest, name) {
|
||||
|
|
|
@ -79,21 +79,21 @@ func newDesignate(p2pSigExtensionsEnabled bool) *Designate {
|
|||
manifest.NewParameter("role", smartcontract.IntegerType),
|
||||
manifest.NewParameter("index", smartcontract.IntegerType))
|
||||
md := newMethodAndPrice(s.getDesignatedByRole, 1000000, smartcontract.AllowStates)
|
||||
s.AddMethod(md, desc, false)
|
||||
s.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("designateAsRole", smartcontract.VoidType,
|
||||
manifest.NewParameter("role", smartcontract.IntegerType),
|
||||
manifest.NewParameter("nodes", smartcontract.ArrayType))
|
||||
md = newMethodAndPrice(s.designateAsRole, 0, smartcontract.AllowModifyStates)
|
||||
s.AddMethod(md, desc, false)
|
||||
s.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("onPersist", smartcontract.VoidType)
|
||||
md = newMethodAndPrice(getOnPersistWrapper(onPersistBase), 0, smartcontract.AllowModifyStates)
|
||||
s.AddMethod(md, desc, false)
|
||||
s.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("postPersist", smartcontract.VoidType)
|
||||
md = newMethodAndPrice(getOnPersistWrapper(postPersistBase), 0, smartcontract.AllowModifyStates)
|
||||
s.AddMethod(md, desc, false)
|
||||
s.AddMethod(md, desc)
|
||||
|
||||
return s
|
||||
}
|
||||
|
|
|
@ -121,44 +121,44 @@ func newNEO() *NEO {
|
|||
manifest.NewParameter("account", smartcontract.Hash160Type),
|
||||
manifest.NewParameter("end", smartcontract.IntegerType))
|
||||
md := newMethodAndPrice(n.unclaimedGas, 3000000, smartcontract.AllowStates)
|
||||
n.AddMethod(md, desc, true)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("registerCandidate", smartcontract.BoolType,
|
||||
manifest.NewParameter("pubkey", smartcontract.PublicKeyType))
|
||||
md = newMethodAndPrice(n.registerCandidate, 5000000, smartcontract.AllowModifyStates)
|
||||
n.AddMethod(md, desc, false)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("unregisterCandidate", smartcontract.BoolType,
|
||||
manifest.NewParameter("pubkey", smartcontract.PublicKeyType))
|
||||
md = newMethodAndPrice(n.unregisterCandidate, 5000000, smartcontract.AllowModifyStates)
|
||||
n.AddMethod(md, desc, false)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("vote", smartcontract.BoolType,
|
||||
manifest.NewParameter("account", smartcontract.Hash160Type),
|
||||
manifest.NewParameter("pubkey", smartcontract.PublicKeyType))
|
||||
md = newMethodAndPrice(n.vote, 5000000, smartcontract.AllowModifyStates)
|
||||
n.AddMethod(md, desc, false)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("getCandidates", smartcontract.ArrayType)
|
||||
md = newMethodAndPrice(n.getCandidatesCall, 100000000, smartcontract.AllowStates)
|
||||
n.AddMethod(md, desc, true)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("getСommittee", smartcontract.ArrayType)
|
||||
md = newMethodAndPrice(n.getCommittee, 100000000, smartcontract.AllowStates)
|
||||
n.AddMethod(md, desc, true)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("getNextBlockValidators", smartcontract.ArrayType)
|
||||
md = newMethodAndPrice(n.getNextBlockValidators, 100000000, smartcontract.AllowStates)
|
||||
n.AddMethod(md, desc, true)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("getGasPerBlock", smartcontract.IntegerType)
|
||||
md = newMethodAndPrice(n.getGASPerBlock, 100_0000, smartcontract.AllowStates)
|
||||
n.AddMethod(md, desc, false)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("setGasPerBlock", smartcontract.BoolType,
|
||||
manifest.NewParameter("gasPerBlock", smartcontract.IntegerType))
|
||||
md = newMethodAndPrice(n.setGASPerBlock, 500_0000, smartcontract.AllowModifyStates)
|
||||
n.AddMethod(md, desc, false)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
return n
|
||||
}
|
||||
|
|
|
@ -56,20 +56,20 @@ func newNEP17Native(name string) *nep17TokenNative {
|
|||
|
||||
desc := newDescriptor("symbol", smartcontract.StringType)
|
||||
md := newMethodAndPrice(n.Symbol, 0, smartcontract.NoneFlag)
|
||||
n.AddMethod(md, desc, true)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("decimals", smartcontract.IntegerType)
|
||||
md = newMethodAndPrice(n.Decimals, 0, smartcontract.NoneFlag)
|
||||
n.AddMethod(md, desc, true)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("totalSupply", smartcontract.IntegerType)
|
||||
md = newMethodAndPrice(n.TotalSupply, 1000000, smartcontract.AllowStates)
|
||||
n.AddMethod(md, desc, true)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("balanceOf", smartcontract.IntegerType,
|
||||
manifest.NewParameter("account", smartcontract.Hash160Type))
|
||||
md = newMethodAndPrice(n.balanceOf, 1000000, smartcontract.AllowStates)
|
||||
n.AddMethod(md, desc, true)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
transferParams := []manifest.Parameter{
|
||||
manifest.NewParameter("from", smartcontract.Hash160Type),
|
||||
|
@ -80,15 +80,15 @@ func newNEP17Native(name string) *nep17TokenNative {
|
|||
append(transferParams, manifest.NewParameter("data", smartcontract.AnyType))...,
|
||||
)
|
||||
md = newMethodAndPrice(n.Transfer, 8000000, smartcontract.AllowModifyStates)
|
||||
n.AddMethod(md, desc, false)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("onPersist", smartcontract.VoidType)
|
||||
md = newMethodAndPrice(getOnPersistWrapper(onPersistBase), 0, smartcontract.AllowModifyStates)
|
||||
n.AddMethod(md, desc, false)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("postPersist", smartcontract.VoidType)
|
||||
md = newMethodAndPrice(getOnPersistWrapper(postPersistBase), 0, smartcontract.AllowModifyStates)
|
||||
n.AddMethod(md, desc, false)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
n.AddEvent("Transfer", transferParams...)
|
||||
|
||||
|
|
|
@ -47,42 +47,42 @@ func newNotary() *Notary {
|
|||
manifest.NewParameter("amount", smartcontract.IntegerType),
|
||||
manifest.NewParameter("data", smartcontract.AnyType))
|
||||
md := newMethodAndPrice(n.onPayment, 100_0000, smartcontract.AllowModifyStates)
|
||||
n.AddMethod(md, desc, true)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("lockDepositUntil", smartcontract.BoolType,
|
||||
manifest.NewParameter("address", smartcontract.Hash160Type),
|
||||
manifest.NewParameter("till", smartcontract.IntegerType))
|
||||
md = newMethodAndPrice(n.lockDepositUntil, 100_0000, smartcontract.AllowModifyStates)
|
||||
n.AddMethod(md, desc, true)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("withdraw", smartcontract.BoolType,
|
||||
manifest.NewParameter("from", smartcontract.Hash160Type),
|
||||
manifest.NewParameter("to", smartcontract.Hash160Type))
|
||||
md = newMethodAndPrice(n.withdraw, 100_0000, smartcontract.AllowModifyStates)
|
||||
n.AddMethod(md, desc, true)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("balanceOf", smartcontract.IntegerType,
|
||||
manifest.NewParameter("addr", smartcontract.Hash160Type))
|
||||
md = newMethodAndPrice(n.balanceOf, 100_0000, smartcontract.AllowStates)
|
||||
n.AddMethod(md, desc, true)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("expirationOf", smartcontract.IntegerType,
|
||||
manifest.NewParameter("addr", smartcontract.Hash160Type))
|
||||
md = newMethodAndPrice(n.expirationOf, 100_0000, smartcontract.AllowStates)
|
||||
n.AddMethod(md, desc, true)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("verify", smartcontract.BoolType,
|
||||
manifest.NewParameter("signature", smartcontract.SignatureType))
|
||||
md = newMethodAndPrice(n.verify, 100_0000, smartcontract.AllowStates)
|
||||
n.AddMethod(md, desc, false)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("onPersist", smartcontract.VoidType)
|
||||
md = newMethodAndPrice(getOnPersistWrapper(n.OnPersist), 0, smartcontract.AllowModifyStates)
|
||||
n.AddMethod(md, desc, false)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("postPersist", smartcontract.VoidType)
|
||||
md = newMethodAndPrice(getOnPersistWrapper(postPersistBase), 0, smartcontract.AllowModifyStates)
|
||||
n.AddMethod(md, desc, false)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
return n
|
||||
}
|
||||
|
|
|
@ -111,24 +111,24 @@ func newOracle() *Oracle {
|
|||
manifest.NewParameter("userData", smartcontract.AnyType),
|
||||
manifest.NewParameter("gasForResponse", smartcontract.IntegerType))
|
||||
md := newMethodAndPrice(o.request, oracleRequestPrice, smartcontract.AllowModifyStates)
|
||||
o.AddMethod(md, desc, false)
|
||||
o.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("finish", smartcontract.VoidType)
|
||||
md = newMethodAndPrice(o.finish, 0, smartcontract.AllowModifyStates)
|
||||
o.AddMethod(md, desc, false)
|
||||
o.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("verify", smartcontract.BoolType)
|
||||
md = newMethodAndPrice(o.verify, 100_0000, smartcontract.NoneFlag)
|
||||
o.AddMethod(md, desc, false)
|
||||
o.AddMethod(md, desc)
|
||||
|
||||
pp := chainOnPersist(postPersistBase, o.PostPersist)
|
||||
desc = newDescriptor("postPersist", smartcontract.VoidType)
|
||||
md = newMethodAndPrice(getOnPersistWrapper(pp), 0, smartcontract.AllowModifyStates)
|
||||
o.AddMethod(md, desc, false)
|
||||
o.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("onPersist", smartcontract.VoidType)
|
||||
md = newMethodAndPrice(getOnPersistWrapper(onPersistBase), 0, smartcontract.AllowModifyStates)
|
||||
o.AddMethod(md, desc, false)
|
||||
o.AddMethod(md, desc)
|
||||
|
||||
o.AddEvent("OracleRequest", manifest.NewParameter("Id", smartcontract.IntegerType),
|
||||
manifest.NewParameter("RequestContract", smartcontract.Hash160Type),
|
||||
|
|
|
@ -77,62 +77,62 @@ func newPolicy() *Policy {
|
|||
|
||||
desc := newDescriptor("getMaxTransactionsPerBlock", smartcontract.IntegerType)
|
||||
md := newMethodAndPrice(p.getMaxTransactionsPerBlock, 1000000, smartcontract.AllowStates)
|
||||
p.AddMethod(md, desc, true)
|
||||
p.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("getMaxBlockSize", smartcontract.IntegerType)
|
||||
md = newMethodAndPrice(p.getMaxBlockSize, 1000000, smartcontract.AllowStates)
|
||||
p.AddMethod(md, desc, true)
|
||||
p.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("getFeePerByte", smartcontract.IntegerType)
|
||||
md = newMethodAndPrice(p.getFeePerByte, 1000000, smartcontract.AllowStates)
|
||||
p.AddMethod(md, desc, true)
|
||||
p.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("isBlocked", smartcontract.BoolType,
|
||||
manifest.NewParameter("account", smartcontract.Hash160Type))
|
||||
md = newMethodAndPrice(p.isBlocked, 1000000, smartcontract.AllowStates)
|
||||
p.AddMethod(md, desc, true)
|
||||
p.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("getMaxBlockSystemFee", smartcontract.IntegerType)
|
||||
md = newMethodAndPrice(p.getMaxBlockSystemFee, 1000000, smartcontract.AllowStates)
|
||||
p.AddMethod(md, desc, true)
|
||||
p.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("setMaxBlockSize", smartcontract.BoolType,
|
||||
manifest.NewParameter("value", smartcontract.IntegerType))
|
||||
md = newMethodAndPrice(p.setMaxBlockSize, 3000000, smartcontract.AllowModifyStates)
|
||||
p.AddMethod(md, desc, false)
|
||||
p.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("setMaxTransactionsPerBlock", smartcontract.BoolType,
|
||||
manifest.NewParameter("value", smartcontract.IntegerType))
|
||||
md = newMethodAndPrice(p.setMaxTransactionsPerBlock, 3000000, smartcontract.AllowModifyStates)
|
||||
p.AddMethod(md, desc, false)
|
||||
p.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("setFeePerByte", smartcontract.BoolType,
|
||||
manifest.NewParameter("value", smartcontract.IntegerType))
|
||||
md = newMethodAndPrice(p.setFeePerByte, 3000000, smartcontract.AllowModifyStates)
|
||||
p.AddMethod(md, desc, false)
|
||||
p.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("setMaxBlockSystemFee", smartcontract.BoolType,
|
||||
manifest.NewParameter("value", smartcontract.IntegerType))
|
||||
md = newMethodAndPrice(p.setMaxBlockSystemFee, 3000000, smartcontract.AllowModifyStates)
|
||||
p.AddMethod(md, desc, false)
|
||||
p.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("blockAccount", smartcontract.BoolType,
|
||||
manifest.NewParameter("account", smartcontract.Hash160Type))
|
||||
md = newMethodAndPrice(p.blockAccount, 3000000, smartcontract.AllowModifyStates)
|
||||
p.AddMethod(md, desc, false)
|
||||
p.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("unblockAccount", smartcontract.BoolType,
|
||||
manifest.NewParameter("account", smartcontract.Hash160Type))
|
||||
md = newMethodAndPrice(p.unblockAccount, 3000000, smartcontract.AllowModifyStates)
|
||||
p.AddMethod(md, desc, false)
|
||||
p.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("onPersist", smartcontract.VoidType)
|
||||
md = newMethodAndPrice(getOnPersistWrapper(p.OnPersist), 0, smartcontract.AllowModifyStates)
|
||||
p.AddMethod(md, desc, false)
|
||||
p.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("postPersist", smartcontract.VoidType)
|
||||
md = newMethodAndPrice(getOnPersistWrapper(postPersistBase), 0, smartcontract.AllowModifyStates)
|
||||
p.AddMethod(md, desc, false)
|
||||
p.AddMethod(md, desc)
|
||||
return p
|
||||
}
|
||||
|
||||
|
|
|
@ -66,13 +66,14 @@ func newTestNative() *testNative {
|
|||
manifest.NewParameter("addend2", smartcontract.IntegerType),
|
||||
},
|
||||
ReturnType: smartcontract.IntegerType,
|
||||
Safe: true,
|
||||
}
|
||||
md := &interop.MethodAndPrice{
|
||||
Func: tn.sum,
|
||||
Price: testSumPrice,
|
||||
RequiredFlags: smartcontract.NoneFlag,
|
||||
}
|
||||
tn.meta.AddMethod(md, desc, true)
|
||||
tn.meta.AddMethod(md, desc)
|
||||
|
||||
desc = &manifest.Method{
|
||||
Name: "callOtherContractNoReturn",
|
||||
|
@ -82,16 +83,17 @@ func newTestNative() *testNative {
|
|||
manifest.NewParameter("arg", smartcontract.ArrayType),
|
||||
},
|
||||
ReturnType: smartcontract.VoidType,
|
||||
Safe: true,
|
||||
}
|
||||
md = &interop.MethodAndPrice{
|
||||
Func: tn.callOtherContractNoReturn,
|
||||
Price: testSumPrice,
|
||||
RequiredFlags: smartcontract.NoneFlag}
|
||||
tn.meta.AddMethod(md, desc, true)
|
||||
tn.meta.AddMethod(md, desc)
|
||||
|
||||
desc = &manifest.Method{Name: "onPersist", ReturnType: smartcontract.BoolType}
|
||||
md = &interop.MethodAndPrice{Func: tn.OnPersist, RequiredFlags: smartcontract.AllowModifyStates}
|
||||
tn.meta.AddMethod(md, desc, false)
|
||||
tn.meta.AddMethod(md, desc)
|
||||
|
||||
return tn
|
||||
}
|
||||
|
|
|
@ -49,8 +49,6 @@ type Manifest struct {
|
|||
SupportedStandards []string `json:"supportedstandards"`
|
||||
// Trusts is a set of hashes to a which contract trusts.
|
||||
Trusts WildUint160s `json:"trusts"`
|
||||
// SafeMethods is a set of names of safe methods.
|
||||
SafeMethods WildStrings `json:"safemethods"`
|
||||
// Extra is an implementation-defined user data.
|
||||
Extra interface{} `json:"extra"`
|
||||
}
|
||||
|
@ -67,7 +65,6 @@ func NewManifest(name string) *Manifest {
|
|||
SupportedStandards: []string{},
|
||||
}
|
||||
m.Trusts.Restrict()
|
||||
m.SafeMethods.Restrict()
|
||||
return m
|
||||
}
|
||||
|
||||
|
@ -101,10 +98,6 @@ func (a *ABI) GetEvent(name string) *Event {
|
|||
// CanCall returns true is current contract is allowed to call
|
||||
// method of another contract with specified hash.
|
||||
func (m *Manifest) CanCall(hash util.Uint160, 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(hash, toCall, method) {
|
||||
return true
|
||||
|
|
|
@ -13,33 +13,33 @@ import (
|
|||
// https://github.com/neo-project/neo/blob/master/tests/neo.UnitTests/SmartContract/Manifest/UT_ContractManifest.cs#L10
|
||||
func TestManifest_MarshalJSON(t *testing.T) {
|
||||
t.Run("default", func(t *testing.T) {
|
||||
s := `{"groups":[],"supportedstandards":[],"name":"Test","abi":{"methods":[],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"safemethods":[],"extra":null}`
|
||||
s := `{"groups":[],"supportedstandards":[],"name":"Test","abi":{"methods":[],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null}`
|
||||
m := testUnmarshalMarshalManifest(t, s)
|
||||
require.Equal(t, DefaultManifest("Test"), m)
|
||||
})
|
||||
|
||||
t.Run("permissions", func(t *testing.T) {
|
||||
s := `{"groups":[],"supportedstandards":[],"name":"Test","abi":{"methods":[],"events":[]},"permissions":[{"contract":"0x0000000000000000000000000000000000000000","methods":["method1","method2"]}],"trusts":[],"safemethods":[],"extra":null}`
|
||||
s := `{"groups":[],"supportedstandards":[],"name":"Test","abi":{"methods":[],"events":[]},"permissions":[{"contract":"0x0000000000000000000000000000000000000000","methods":["method1","method2"]}],"trusts":[],"extra":null}`
|
||||
testUnmarshalMarshalManifest(t, s)
|
||||
})
|
||||
|
||||
t.Run("safe methods", func(t *testing.T) {
|
||||
s := `{"groups":[],"supportedstandards":[],"name":"Test","abi":{"methods":[],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"safemethods":["balanceOf"],"extra":null}`
|
||||
s := `{"groups":[],"supportedstandards":[],"name":"Test","abi":{"methods":[{"name":"safeMet","offset":123,"parameters":[],"returntype":"Integer","safe":true}],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null}`
|
||||
testUnmarshalMarshalManifest(t, s)
|
||||
})
|
||||
|
||||
t.Run("trust", func(t *testing.T) {
|
||||
s := `{"groups":[],"supportedstandards":[],"name":"Test","abi":{"methods":[],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":["0x0000000000000000000000000000000000000001"],"safemethods":[],"extra":null}`
|
||||
s := `{"groups":[],"supportedstandards":[],"name":"Test","abi":{"methods":[],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":["0x0000000000000000000000000000000000000001"],"extra":null}`
|
||||
testUnmarshalMarshalManifest(t, s)
|
||||
})
|
||||
|
||||
t.Run("groups", func(t *testing.T) {
|
||||
s := `{"groups":[{"pubkey":"03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c","signature":"QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQQ=="}],"supportedstandards":[],"name":"Test","abi":{"methods":[],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"safemethods":[],"extra":null}`
|
||||
s := `{"groups":[{"pubkey":"03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c","signature":"QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQQ=="}],"supportedstandards":[],"name":"Test","abi":{"methods":[],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null}`
|
||||
testUnmarshalMarshalManifest(t, s)
|
||||
})
|
||||
|
||||
t.Run("extra", func(t *testing.T) {
|
||||
s := `{"groups":[],"supportedstandards":[],"name":"Test","abi":{"methods":[],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"safemethods":[],"extra":{"key":"value"}}`
|
||||
s := `{"groups":[],"supportedstandards":[],"name":"Test","abi":{"methods":[],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":{"key":"value"}}`
|
||||
testUnmarshalMarshalManifest(t, s)
|
||||
})
|
||||
}
|
||||
|
@ -57,19 +57,9 @@ func testUnmarshalMarshalManifest(t *testing.T, s string) *Manifest {
|
|||
}
|
||||
|
||||
func TestManifest_CanCall(t *testing.T) {
|
||||
t.Run("safe methods", func(t *testing.T) {
|
||||
man1 := NewManifest("Test1")
|
||||
man2 := DefaultManifest("Test2")
|
||||
require.False(t, man1.CanCall(util.Uint160{}, man2, "method1"))
|
||||
man2.SafeMethods.Add("method1")
|
||||
require.True(t, man1.CanCall(util.Uint160{}, man2, "method1"))
|
||||
})
|
||||
|
||||
t.Run("wildcard permission", func(t *testing.T) {
|
||||
man1 := DefaultManifest("Test1")
|
||||
man2 := DefaultManifest("Test2")
|
||||
require.True(t, man1.CanCall(util.Uint160{}, man2, "method1"))
|
||||
})
|
||||
man1 := DefaultManifest("Test1")
|
||||
man2 := DefaultManifest("Test2")
|
||||
require.True(t, man1.CanCall(util.Uint160{}, man2, "method1"))
|
||||
}
|
||||
|
||||
func TestPermission_IsAllowed(t *testing.T) {
|
||||
|
|
|
@ -41,6 +41,7 @@ type Method struct {
|
|||
Offset int `json:"offset"`
|
||||
Parameters []Parameter `json:"parameters"`
|
||||
ReturnType smartcontract.ParamType `json:"returntype"`
|
||||
Safe bool `json:"safe"`
|
||||
}
|
||||
|
||||
// NewParameter returns new parameter of specified name and type.
|
||||
|
|
|
@ -14,6 +14,7 @@ var (
|
|||
ErrInvalidReturnType = errors.New("invalid return type")
|
||||
ErrInvalidParameterCount = errors.New("invalid parameter count")
|
||||
ErrInvalidParameterType = errors.New("invalid parameter type")
|
||||
ErrSafeMethodMismatch = errors.New("method has wrong safe flag")
|
||||
)
|
||||
|
||||
var checks = map[string]*manifest.Manifest{
|
||||
|
@ -55,6 +56,9 @@ func Comply(m, st *manifest.Manifest) error {
|
|||
name, i, stm.Parameters[i].Type, md.Parameters[i].Type)
|
||||
}
|
||||
}
|
||||
if stm.Safe != md.Safe {
|
||||
return fmt.Errorf("%w: expected %t", ErrSafeMethodMismatch, stm.Safe)
|
||||
}
|
||||
}
|
||||
for _, ste := range st.ABI.Events {
|
||||
name := ste.Name
|
||||
|
|
|
@ -20,6 +20,7 @@ func fooMethodBarEvent() *manifest.Manifest {
|
|||
{Type: smartcontract.PublicKeyType},
|
||||
},
|
||||
ReturnType: smartcontract.IntegerType,
|
||||
Safe: true,
|
||||
},
|
||||
},
|
||||
Events: []manifest.Event{
|
||||
|
@ -87,6 +88,13 @@ func TestMissingEvent(t *testing.T) {
|
|||
require.True(t, errors.Is(err, ErrEventMissing))
|
||||
}
|
||||
|
||||
func TestSafeFlag(t *testing.T) {
|
||||
m := fooMethodBarEvent()
|
||||
m.ABI.GetMethod("foo").Safe = false
|
||||
err := Comply(m, fooMethodBarEvent())
|
||||
require.True(t, errors.Is(err, ErrSafeMethodMismatch))
|
||||
}
|
||||
|
||||
func TestComplyValid(t *testing.T) {
|
||||
m := fooMethodBarEvent()
|
||||
m.ABI.Methods = append(m.ABI.Methods, manifest.Method{
|
||||
|
|
Loading…
Reference in a new issue