Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

interop: use executing contract state for permissions checks #3472

Merged
merged 1 commit into from
Jun 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cli/vm/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -1105,7 +1105,7 @@ func handleRun(c *cli.Context) error {
breaks := v.Context().BreakPoints() // We ensure that there's a context loaded.
ic.ReuseVM(v)
v.GasLimit = gasLimit
v.LoadNEFMethod(&cs.NEF, util.Uint160{}, cs.Hash, callflag.All, hasRet, offset, initOff, nil)
v.LoadNEFMethod(&cs.NEF, &cs.Manifest, util.Uint160{}, cs.Hash, callflag.All, hasRet, offset, initOff, nil)
for _, bp := range breaks {
v.AddBreakPoint(bp)
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -2928,7 +2928,7 @@ func (bc *Blockchain) InitVerificationContext(ic *interop.Context, hash util.Uin
initOffset = md.Offset
}
ic.Invocations[cs.Hash]++
ic.VM.LoadNEFMethod(&cs.NEF, util.Uint160{}, hash, callflag.ReadOnly,
ic.VM.LoadNEFMethod(&cs.NEF, &cs.Manifest, util.Uint160{}, hash, callflag.ReadOnly,
true, verifyOffset, initOffset, nil)
}
if len(witness.InvocationScript) != 0 {
Expand Down
2 changes: 1 addition & 1 deletion pkg/core/interop/contract/call.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ func callExFromNative(ic *interop.Context, caller util.Uint160, cs *state.Contra
}
return nil
}
ic.VM.LoadNEFMethod(&cs.NEF, caller, cs.Hash, f,
ic.VM.LoadNEFMethod(&cs.NEF, &cs.Manifest, caller, cs.Hash, f,
hasReturn, methodOff, initOff, onUnload)

for e, i := ic.VM.Estack(), len(args)-1; i >= 0; i-- {
Expand Down
10 changes: 5 additions & 5 deletions pkg/core/interop/runtime/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,19 +80,19 @@ func Notify(ic *interop.Context) error {
if len(name) > MaxEventNameLen {
return fmt.Errorf("event name must be less than %d", MaxEventNameLen)
}
curHash := ic.VM.GetCurrentScriptHash()
ctr, err := ic.GetContract(curHash)
if err != nil {
curr := ic.VM.Context().GetManifest()
if curr == nil {
return errors.New("notifications are not allowed in dynamic scripts")
}
var (
ev = ctr.Manifest.ABI.GetEvent(name)
ev = curr.ABI.GetEvent(name)
checkErr error
curHash = ic.VM.GetCurrentScriptHash()
)
if ev == nil {
checkErr = fmt.Errorf("notification %s does not exist", name)
} else {
err = ev.CheckCompliance(args)
err := ev.CheckCompliance(args)
if err != nil {
checkErr = fmt.Errorf("notification %s is invalid: %w", name, err)
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/core/interop/runtime/ext_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -637,7 +637,7 @@ func TestNotify(t *testing.T) {
_, _, bc, cs := getDeployedInternal(t)
ic, err := bc.GetTestVM(trigger.Application, nil, nil)
require.NoError(t, err)
ic.VM.LoadNEFMethod(&cs.NEF, caller, cs.Hash, callflag.NoneFlag, true, 0, -1, nil)
ic.VM.LoadNEFMethod(&cs.NEF, &cs.Manifest, caller, cs.Hash, callflag.NoneFlag, true, 0, -1, nil)
ic.VM.Estack().PushVal(args)
ic.VM.Estack().PushVal(name)
return ic
Expand Down
8 changes: 8 additions & 0 deletions pkg/vm/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/invocations"
Expand Down Expand Up @@ -44,6 +45,8 @@ type scriptContext struct {

// NEF represents a NEF file for the current contract.
NEF *nef.File
// Manifest represents a manifest for the current contract.
Manifest *manifest.Manifest
// invTree is an invocation tree (or a branch of it) for this context.
invTree *invocations.Tree
// onUnload is a callback that should be called after current context unloading
Expand Down Expand Up @@ -249,6 +252,11 @@ func (c *Context) GetNEF() *nef.File {
return c.sc.NEF
}

// GetManifest returns Manifest used by this context if it's present.
func (c *Context) GetManifest() *manifest.Manifest {
return c.sc.Manifest
}

// NumOfReturnVals returns the number of return values expected from this context.
func (c *Context) NumOfReturnVals() int {
return c.retCount
Expand Down
2 changes: 1 addition & 1 deletion pkg/vm/debug_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,6 @@ func TestContext_BreakPoints(t *testing.T) {
require.Equal(t, []int{3, 5}, v.Context().BreakPoints())

// New context -> clean breakpoints.
v.loadScriptWithCallingHash(prog, nil, util.Uint160{}, util.Uint160{}, callflag.All, 1, 3, nil)
v.loadScriptWithCallingHash(prog, nil, nil, util.Uint160{}, util.Uint160{}, callflag.All, 1, 3, nil)
require.Equal(t, []int{}, v.Context().BreakPoints())
}
14 changes: 8 additions & 6 deletions pkg/vm/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
"github.com/nspcc-dev/neo-go/pkg/util"
Expand Down Expand Up @@ -308,14 +309,14 @@ func (v *VM) LoadScript(b []byte) {

// LoadScriptWithFlags loads script and sets call flag to f.
func (v *VM) LoadScriptWithFlags(b []byte, f callflag.CallFlag) {
v.loadScriptWithCallingHash(b, nil, v.GetCurrentScriptHash(), util.Uint160{}, f, -1, 0, nil)
v.loadScriptWithCallingHash(b, nil, nil, v.GetCurrentScriptHash(), util.Uint160{}, f, -1, 0, nil)
}

// LoadDynamicScript loads the given script with the given flags. This script is
// considered to be dynamic, it can either return no value at all or return
// exactly one value.
func (v *VM) LoadDynamicScript(b []byte, f callflag.CallFlag) {
v.loadScriptWithCallingHash(b, nil, v.GetCurrentScriptHash(), util.Uint160{}, f, -1, 0, DynamicOnUnload)
v.loadScriptWithCallingHash(b, nil, nil, v.GetCurrentScriptHash(), util.Uint160{}, f, -1, 0, DynamicOnUnload)
}

// LoadScriptWithHash is similar to the LoadScriptWithFlags method, but it also loads
Expand All @@ -325,27 +326,27 @@ func (v *VM) LoadDynamicScript(b []byte, f callflag.CallFlag) {
// accordingly). It's up to the user of this function to make sure the script and hash match
// each other.
func (v *VM) LoadScriptWithHash(b []byte, hash util.Uint160, f callflag.CallFlag) {
v.loadScriptWithCallingHash(b, nil, v.GetCurrentScriptHash(), hash, f, 1, 0, nil)
v.loadScriptWithCallingHash(b, nil, nil, v.GetCurrentScriptHash(), hash, f, 1, 0, nil)
}

// LoadNEFMethod allows to create a context to execute a method from the NEF
// file with the specified caller and executing hash, call flags, return value,
// method and _initialize offsets.
func (v *VM) LoadNEFMethod(exe *nef.File, caller util.Uint160, hash util.Uint160, f callflag.CallFlag,
func (v *VM) LoadNEFMethod(exe *nef.File, manifest *manifest.Manifest, caller util.Uint160, hash util.Uint160, f callflag.CallFlag,
hasReturn bool, methodOff int, initOff int, onContextUnload ContextUnloadCallback) {
var rvcount int
if hasReturn {
rvcount = 1
}
v.loadScriptWithCallingHash(exe.Script, exe, caller, hash, f, rvcount, methodOff, onContextUnload)
v.loadScriptWithCallingHash(exe.Script, exe, manifest, caller, hash, f, rvcount, methodOff, onContextUnload)
if initOff >= 0 {
v.Call(initOff)
}
}

// loadScriptWithCallingHash is similar to LoadScriptWithHash but sets calling hash explicitly.
// It should be used for calling from native contracts.
func (v *VM) loadScriptWithCallingHash(b []byte, exe *nef.File, caller util.Uint160,
func (v *VM) loadScriptWithCallingHash(b []byte, exe *nef.File, manifest *manifest.Manifest, caller util.Uint160,
hash util.Uint160, f callflag.CallFlag, rvcount int, offset int, onContextUnload ContextUnloadCallback) {
v.checkInvocationStackSize()
ctx := NewContextWithParams(b, rvcount, offset)
Expand All @@ -363,6 +364,7 @@ func (v *VM) loadScriptWithCallingHash(b []byte, exe *nef.File, caller util.Uint
ctx.sc.scriptHash = hash
ctx.sc.callingScriptHash = caller
ctx.sc.NEF = exe
ctx.sc.Manifest = manifest
if v.invTree != nil {
curTree := v.invTree
if parent != nil {
Expand Down
Loading