interop/native: always use proper ScriptHashGetter, fix #924

All scripts are run in VM, so it's there to tell us about script hashes
involved and it must be used instead of nep5ScriptHash kludge.
This commit is contained in:
Roman Khimov 2020-07-15 22:43:30 +03:00
parent aee200720d
commit d4c3a17883
6 changed files with 11 additions and 44 deletions

View file

@ -31,6 +31,7 @@ type Context struct {
Notifications []state.NotificationEvent Notifications []state.NotificationEvent
Log *zap.Logger Log *zap.Logger
Invocations map[util.Uint160]int Invocations map[util.Uint160]int
ScriptGetter vm.ScriptHashGetter
} }
// NewContext returns new interop context. // NewContext returns new interop context.

View file

@ -12,9 +12,9 @@ import (
// CheckHashedWitness checks given hash against current list of script hashes // CheckHashedWitness checks given hash against current list of script hashes
// for verifying in the interop context. // for verifying in the interop context.
func CheckHashedWitness(ic *interop.Context, v vm.ScriptHashGetter, hash util.Uint160) (bool, error) { func CheckHashedWitness(ic *interop.Context, hash util.Uint160) (bool, error) {
if tx, ok := ic.Container.(*transaction.Transaction); ok { if tx, ok := ic.Container.(*transaction.Transaction); ok {
return checkScope(ic.DAO, tx, v, hash) return checkScope(ic.DAO, tx, ic.ScriptGetter, hash)
} }
// only for non-Transaction types (Block, etc.) // only for non-Transaction types (Block, etc.)
@ -77,8 +77,8 @@ func checkScope(d dao.DAO, tx *transaction.Transaction, v vm.ScriptHashGetter, h
// CheckKeyedWitness checks hash of signature check contract with a given public // CheckKeyedWitness checks hash of signature check contract with a given public
// key against current list of script hashes for verifying in the interop context. // key against current list of script hashes for verifying in the interop context.
func CheckKeyedWitness(ic *interop.Context, v vm.ScriptHashGetter, key *keys.PublicKey) (bool, error) { func CheckKeyedWitness(ic *interop.Context, key *keys.PublicKey) (bool, error) {
return CheckHashedWitness(ic, v, key.GetScriptHash()) return CheckHashedWitness(ic, key.GetScriptHash())
} }
// CheckWitness checks witnesses. // CheckWitness checks witnesses.
@ -94,9 +94,9 @@ func CheckWitness(ic *interop.Context, v *vm.VM) error {
if err != nil { if err != nil {
return errors.New("parameter given is neither a key nor a hash") return errors.New("parameter given is neither a key nor a hash")
} }
res, err = CheckKeyedWitness(ic, v, key) res, err = CheckKeyedWitness(ic, key)
} else { } else {
res, err = CheckHashedWitness(ic, v, hash) res, err = CheckHashedWitness(ic, hash)
} }
if err != nil { if err != nil {
return errors.Wrap(err, "failed to check") return errors.Wrap(err, "failed to check")

View file

@ -32,6 +32,7 @@ func SpawnVM(ic *interop.Context) *vm.VM {
if ic.Chain != nil { if ic.Chain != nil {
vm.RegisterInteropGetter(ic.Chain.(*Blockchain).contracts.GetNativeInterop(ic)) vm.RegisterInteropGetter(ic.Chain.(*Blockchain).contracts.GetNativeInterop(ic))
} }
ic.ScriptGetter = vm
return vm return vm
} }

View file

@ -253,11 +253,7 @@ func (n *NEO) vote(ic *interop.Context, args []stackitem.Item) stackitem.Item {
// VoteInternal votes from account h for validarors specified in pubs. // VoteInternal votes from account h for validarors specified in pubs.
func (n *NEO) VoteInternal(ic *interop.Context, h util.Uint160, pubs keys.PublicKeys) error { func (n *NEO) VoteInternal(ic *interop.Context, h util.Uint160, pubs keys.PublicKeys) error {
ok, err := runtime.CheckHashedWitness(ic, nep5ScriptHash{ ok, err := runtime.CheckHashedWitness(ic, h)
callingScriptHash: util.Uint160{},
entryScriptHash: n.Hash,
currentScriptHash: n.Hash,
}, h)
if err != nil { if err != nil {
return err return err
} else if !ok { } else if !ok {

View file

@ -175,11 +175,7 @@ func (c *nep5TokenNative) transfer(ic *interop.Context, from, to util.Uint160, a
return errors.New("negative amount") return errors.New("negative amount")
} }
ok, err := runtime.CheckHashedWitness(ic, nep5ScriptHash{ ok, err := runtime.CheckHashedWitness(ic, from)
callingScriptHash: c.Hash,
entryScriptHash: c.Hash,
currentScriptHash: c.Hash,
}, from)
if err != nil { if err != nil {
return err return err
} else if !ok { } else if !ok {
@ -301,29 +297,6 @@ func toUint160(s stackitem.Item) util.Uint160 {
return u return u
} }
// scriptHash is an auxiliary structure which implements ScriptHashGetter
// interface over NEP5 native contract and is used for runtime.CheckHashedWitness
type nep5ScriptHash struct {
callingScriptHash util.Uint160
entryScriptHash util.Uint160
currentScriptHash util.Uint160
}
// GetCallingScriptHash implements ScriptHashGetter interface
func (s nep5ScriptHash) GetCallingScriptHash() util.Uint160 {
return s.callingScriptHash
}
// GetEntryScriptHash implements ScriptHashGetter interface
func (s nep5ScriptHash) GetEntryScriptHash() util.Uint160 {
return s.entryScriptHash
}
// GetCurrentScriptHash implements ScriptHashGetter interface
func (s nep5ScriptHash) GetCurrentScriptHash() util.Uint160 {
return s.currentScriptHash
}
func getOnPersistWrapper(f func(ic *interop.Context) error) interop.Method { func getOnPersistWrapper(f func(ic *interop.Context) error) interop.Method {
return func(ic *interop.Context, _ []stackitem.Item) stackitem.Item { return func(ic *interop.Context, _ []stackitem.Item) stackitem.Item {
return stackitem.NewBool(f(ic) == nil) return stackitem.NewBool(f(ic) == nil)

View file

@ -423,11 +423,7 @@ func (p *Policy) checkValidators(ic *interop.Context) (bool, error) {
if err != nil { if err != nil {
return false, err return false, err
} }
return runtime.CheckHashedWitness(ic, nep5ScriptHash{ return runtime.CheckHashedWitness(ic, prevBlock.NextConsensus)
callingScriptHash: p.Hash,
entryScriptHash: p.Hash,
currentScriptHash: p.Hash,
}, prevBlock.NextConsensus)
} }
// CheckPolicy checks whether transaction's script hashes for verifying are // CheckPolicy checks whether transaction's script hashes for verifying are