contract: avoid going to the DB for entry scripts

This optimizes out DB access for non-deployed contracts under the assumption
that deployed ones are always loaded via `LoadScriptWithHash` (and if they're
not --- it's a bug anyway with the new hashing model) which actually is a very
popular case (every entry script does that).
This commit is contained in:
Roman Khimov 2020-11-26 23:02:00 +03:00
parent 49f6b33eae
commit d93aa745bb
4 changed files with 22 additions and 7 deletions

View file

@ -46,10 +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 '_')")
}
curr, err := ic.DAO.GetContractState(ic.VM.GetCurrentScriptHash())
if err == nil {
if !curr.Manifest.CanCall(u, &cs.Manifest, name) {
return errors.New("disallowed method call")
ctx := ic.VM.Context()
if ctx != nil && ctx.IsDeployed() {
curr, err := ic.DAO.GetContractState(ic.VM.GetCurrentScriptHash())
if err == nil {
if !curr.Manifest.CanCall(u, &cs.Manifest, name) {
return errors.New("disallowed method call")
}
}
}
return CallExInternal(ic, cs, name, args, f, vm.EnsureNotEmpty, nil)

View file

@ -581,7 +581,7 @@ func TestContractCall(t *testing.T) {
runInvalid := func(args ...interface{}) func(t *testing.T) {
return func(t *testing.T) {
loadScript(ic, currScript, 42)
loadScriptWithHashAndFlags(ic, currScript, h, smartcontract.All, 42)
for i := range args {
ic.VM.Estack().PushVal(args[i])
}

View file

@ -42,6 +42,9 @@ type Context struct {
// Caller's contract script hash.
callingScriptHash util.Uint160
// Set to true when running deployed contracts.
isDeployed bool
// Call flags this context was created with.
callFlag smartcontract.CallFlag
@ -256,6 +259,11 @@ func (c *Context) String() string {
return "execution context"
}
// IsDeployed returns whether this context contains deployed contract.
func (c *Context) IsDeployed() bool {
return c.isDeployed
}
// getContextScriptHash returns script hash of the invocation stack element
// number n.
func (v *VM) getContextScriptHash(n int) util.Uint160 {

View file

@ -284,12 +284,16 @@ func (v *VM) LoadScriptWithFlags(b []byte, f smartcontract.CallFlag) {
}
// LoadScriptWithHash if similar to the LoadScriptWithFlags method, but it also loads
// given script hash directly into the Context to avoid its recalculations. It's
// up to user of this function to make sure the script and hash match each other.
// given script hash directly into the Context to avoid its recalculations and to make
// is possible to override it for deployed contracts with special hashes (the function
// assumes that it is used for deployed contracts setting context's parameters
// accordingly). It's up to user of this function to make sure the script and hash match
// each other.
func (v *VM) LoadScriptWithHash(b []byte, hash util.Uint160, f smartcontract.CallFlag) {
shash := v.GetCurrentScriptHash()
v.LoadScriptWithFlags(b, f)
ctx := v.Context()
ctx.isDeployed = true
ctx.scriptHash = hash
ctx.callingScriptHash = shash
}