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