forked from TrueCloudLab/neoneo-go
Merge pull request #3472 from nspcc-dev/pick-proper-exe-context
interop: use executing contract state for permissions checks
This commit is contained in:
commit
45b8af359d
8 changed files with 26 additions and 16 deletions
|
@ -1105,7 +1105,7 @@ func handleRun(c *cli.Context) error {
|
||||||
breaks := v.Context().BreakPoints() // We ensure that there's a context loaded.
|
breaks := v.Context().BreakPoints() // We ensure that there's a context loaded.
|
||||||
ic.ReuseVM(v)
|
ic.ReuseVM(v)
|
||||||
v.GasLimit = gasLimit
|
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 {
|
for _, bp := range breaks {
|
||||||
v.AddBreakPoint(bp)
|
v.AddBreakPoint(bp)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2928,7 +2928,7 @@ func (bc *Blockchain) InitVerificationContext(ic *interop.Context, hash util.Uin
|
||||||
initOffset = md.Offset
|
initOffset = md.Offset
|
||||||
}
|
}
|
||||||
ic.Invocations[cs.Hash]++
|
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)
|
true, verifyOffset, initOffset, nil)
|
||||||
}
|
}
|
||||||
if len(witness.InvocationScript) != 0 {
|
if len(witness.InvocationScript) != 0 {
|
||||||
|
|
|
@ -144,7 +144,7 @@ func callExFromNative(ic *interop.Context, caller util.Uint160, cs *state.Contra
|
||||||
}
|
}
|
||||||
return nil
|
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)
|
hasReturn, methodOff, initOff, onUnload)
|
||||||
|
|
||||||
for e, i := ic.VM.Estack(), len(args)-1; i >= 0; i-- {
|
for e, i := ic.VM.Estack(), len(args)-1; i >= 0; i-- {
|
||||||
|
|
|
@ -80,19 +80,19 @@ func Notify(ic *interop.Context) error {
|
||||||
if len(name) > MaxEventNameLen {
|
if len(name) > MaxEventNameLen {
|
||||||
return fmt.Errorf("event name must be less than %d", MaxEventNameLen)
|
return fmt.Errorf("event name must be less than %d", MaxEventNameLen)
|
||||||
}
|
}
|
||||||
curHash := ic.VM.GetCurrentScriptHash()
|
curr := ic.VM.Context().GetManifest()
|
||||||
ctr, err := ic.GetContract(curHash)
|
if curr == nil {
|
||||||
if err != nil {
|
|
||||||
return errors.New("notifications are not allowed in dynamic scripts")
|
return errors.New("notifications are not allowed in dynamic scripts")
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
ev = ctr.Manifest.ABI.GetEvent(name)
|
ev = curr.ABI.GetEvent(name)
|
||||||
checkErr error
|
checkErr error
|
||||||
|
curHash = ic.VM.GetCurrentScriptHash()
|
||||||
)
|
)
|
||||||
if ev == nil {
|
if ev == nil {
|
||||||
checkErr = fmt.Errorf("notification %s does not exist", name)
|
checkErr = fmt.Errorf("notification %s does not exist", name)
|
||||||
} else {
|
} else {
|
||||||
err = ev.CheckCompliance(args)
|
err := ev.CheckCompliance(args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
checkErr = fmt.Errorf("notification %s is invalid: %w", name, err)
|
checkErr = fmt.Errorf("notification %s is invalid: %w", name, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -637,7 +637,7 @@ func TestNotify(t *testing.T) {
|
||||||
_, _, bc, cs := getDeployedInternal(t)
|
_, _, bc, cs := getDeployedInternal(t)
|
||||||
ic, err := bc.GetTestVM(trigger.Application, nil, nil)
|
ic, err := bc.GetTestVM(trigger.Application, nil, nil)
|
||||||
require.NoError(t, err)
|
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(args)
|
||||||
ic.VM.Estack().PushVal(name)
|
ic.VM.Estack().PushVal(name)
|
||||||
return ic
|
return ic
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
"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/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/nef"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/invocations"
|
"github.com/nspcc-dev/neo-go/pkg/vm/invocations"
|
||||||
|
@ -44,6 +45,8 @@ type scriptContext struct {
|
||||||
|
|
||||||
// NEF represents a NEF file for the current contract.
|
// NEF represents a NEF file for the current contract.
|
||||||
NEF *nef.File
|
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 is an invocation tree (or a branch of it) for this context.
|
||||||
invTree *invocations.Tree
|
invTree *invocations.Tree
|
||||||
// onUnload is a callback that should be called after current context unloading
|
// onUnload is a callback that should be called after current context unloading
|
||||||
|
@ -249,6 +252,11 @@ func (c *Context) GetNEF() *nef.File {
|
||||||
return c.sc.NEF
|
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.
|
// NumOfReturnVals returns the number of return values expected from this context.
|
||||||
func (c *Context) NumOfReturnVals() int {
|
func (c *Context) NumOfReturnVals() int {
|
||||||
return c.retCount
|
return c.retCount
|
||||||
|
|
|
@ -56,6 +56,6 @@ func TestContext_BreakPoints(t *testing.T) {
|
||||||
require.Equal(t, []int{3, 5}, v.Context().BreakPoints())
|
require.Equal(t, []int{3, 5}, v.Context().BreakPoints())
|
||||||
|
|
||||||
// New context -> clean 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())
|
require.Equal(t, []int{}, v.Context().BreakPoints())
|
||||||
}
|
}
|
||||||
|
|
14
pkg/vm/vm.go
14
pkg/vm/vm.go
|
@ -18,6 +18,7 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
"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/encoding/bigint"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
|
"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/nef"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
@ -308,14 +309,14 @@ func (v *VM) LoadScript(b []byte) {
|
||||||
|
|
||||||
// LoadScriptWithFlags loads script and sets call flag to f.
|
// LoadScriptWithFlags loads script and sets call flag to f.
|
||||||
func (v *VM) LoadScriptWithFlags(b []byte, f callflag.CallFlag) {
|
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
|
// 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
|
// considered to be dynamic, it can either return no value at all or return
|
||||||
// exactly one value.
|
// exactly one value.
|
||||||
func (v *VM) LoadDynamicScript(b []byte, f callflag.CallFlag) {
|
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
|
// LoadScriptWithHash is similar to the LoadScriptWithFlags method, but it also loads
|
||||||
|
@ -325,19 +326,19 @@ 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
|
// accordingly). It's up to the user of this function to make sure the script and hash match
|
||||||
// each other.
|
// each other.
|
||||||
func (v *VM) LoadScriptWithHash(b []byte, hash util.Uint160, f callflag.CallFlag) {
|
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
|
// 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,
|
// file with the specified caller and executing hash, call flags, return value,
|
||||||
// method and _initialize offsets.
|
// 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) {
|
hasReturn bool, methodOff int, initOff int, onContextUnload ContextUnloadCallback) {
|
||||||
var rvcount int
|
var rvcount int
|
||||||
if hasReturn {
|
if hasReturn {
|
||||||
rvcount = 1
|
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 {
|
if initOff >= 0 {
|
||||||
v.Call(initOff)
|
v.Call(initOff)
|
||||||
}
|
}
|
||||||
|
@ -345,7 +346,7 @@ func (v *VM) LoadNEFMethod(exe *nef.File, caller util.Uint160, hash util.Uint160
|
||||||
|
|
||||||
// loadScriptWithCallingHash is similar to LoadScriptWithHash but sets calling hash explicitly.
|
// loadScriptWithCallingHash is similar to LoadScriptWithHash but sets calling hash explicitly.
|
||||||
// It should be used for calling from native contracts.
|
// 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) {
|
hash util.Uint160, f callflag.CallFlag, rvcount int, offset int, onContextUnload ContextUnloadCallback) {
|
||||||
v.checkInvocationStackSize()
|
v.checkInvocationStackSize()
|
||||||
ctx := NewContextWithParams(b, rvcount, offset)
|
ctx := NewContextWithParams(b, rvcount, offset)
|
||||||
|
@ -363,6 +364,7 @@ func (v *VM) loadScriptWithCallingHash(b []byte, exe *nef.File, caller util.Uint
|
||||||
ctx.sc.scriptHash = hash
|
ctx.sc.scriptHash = hash
|
||||||
ctx.sc.callingScriptHash = caller
|
ctx.sc.callingScriptHash = caller
|
||||||
ctx.sc.NEF = exe
|
ctx.sc.NEF = exe
|
||||||
|
ctx.sc.Manifest = manifest
|
||||||
if v.invTree != nil {
|
if v.invTree != nil {
|
||||||
curTree := v.invTree
|
curTree := v.invTree
|
||||||
if parent != nil {
|
if parent != nil {
|
||||||
|
|
Loading…
Reference in a new issue