2020-04-13 12:56:41 +00:00
|
|
|
package runtime
|
|
|
|
|
|
|
|
import (
|
2020-07-13 09:59:41 +00:00
|
|
|
"crypto/elliptic"
|
2020-08-06 14:44:08 +00:00
|
|
|
"errors"
|
|
|
|
"fmt"
|
2020-07-13 09:59:41 +00:00
|
|
|
|
2020-06-09 09:27:53 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/dao"
|
2020-04-13 12:56:41 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
2020-04-30 13:00:33 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
2020-04-13 12:56:41 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
2020-08-24 10:18:02 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
2020-04-13 12:56:41 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/vm"
|
|
|
|
)
|
|
|
|
|
|
|
|
// CheckHashedWitness checks given hash against current list of script hashes
|
|
|
|
// for verifying in the interop context.
|
2020-07-15 19:43:30 +00:00
|
|
|
func CheckHashedWitness(ic *interop.Context, hash util.Uint160) (bool, error) {
|
2020-09-29 06:56:19 +00:00
|
|
|
callingSH := ic.VM.GetCallingScriptHash()
|
|
|
|
if !callingSH.Equals(util.Uint160{}) && hash.Equals(callingSH) {
|
|
|
|
return true, nil
|
|
|
|
}
|
2020-04-30 13:00:33 +00:00
|
|
|
if tx, ok := ic.Container.(*transaction.Transaction); ok {
|
2020-08-07 13:58:09 +00:00
|
|
|
return checkScope(ic.DAO, tx, ic.VM, hash)
|
2020-04-30 13:00:33 +00:00
|
|
|
}
|
|
|
|
|
2020-07-21 11:02:47 +00:00
|
|
|
return false, errors.New("script container is not a transaction")
|
2020-04-13 12:56:41 +00:00
|
|
|
}
|
|
|
|
|
2020-08-07 13:58:09 +00:00
|
|
|
func checkScope(d dao.DAO, tx *transaction.Transaction, v *vm.VM, hash util.Uint160) (bool, error) {
|
2020-07-29 16:57:38 +00:00
|
|
|
for _, c := range tx.Signers {
|
2020-04-30 13:00:33 +00:00
|
|
|
if c.Account == hash {
|
|
|
|
if c.Scopes == transaction.Global {
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
if c.Scopes&transaction.CalledByEntry != 0 {
|
|
|
|
callingScriptHash := v.GetCallingScriptHash()
|
|
|
|
entryScriptHash := v.GetEntryScriptHash()
|
2020-09-29 13:38:59 +00:00
|
|
|
if callingScriptHash.Equals(util.Uint160{}) || callingScriptHash == entryScriptHash {
|
2020-04-30 13:00:33 +00:00
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if c.Scopes&transaction.CustomContracts != 0 {
|
|
|
|
currentScriptHash := v.GetCurrentScriptHash()
|
|
|
|
for _, allowedContract := range c.AllowedContracts {
|
|
|
|
if allowedContract == currentScriptHash {
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if c.Scopes&transaction.CustomGroups != 0 {
|
2020-06-09 09:27:53 +00:00
|
|
|
callingScriptHash := v.GetCallingScriptHash()
|
|
|
|
if callingScriptHash.Equals(util.Uint160{}) {
|
2020-04-30 13:00:33 +00:00
|
|
|
return false, nil
|
|
|
|
}
|
2020-12-11 07:34:01 +00:00
|
|
|
if !v.Context().GetCallFlags().Has(smartcontract.ReadStates) {
|
|
|
|
return false, errors.New("missing ReadStates call flag")
|
2020-08-24 10:18:02 +00:00
|
|
|
}
|
2020-06-09 09:27:53 +00:00
|
|
|
cs, err := d.GetContractState(callingScriptHash)
|
2020-04-30 13:00:33 +00:00
|
|
|
if err != nil {
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
// check if the current group is the required one
|
|
|
|
for _, allowedGroup := range c.AllowedGroups {
|
|
|
|
for _, group := range cs.Manifest.Groups {
|
|
|
|
if group.PublicKey.Equal(allowedGroup) {
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
}
|
2020-06-09 09:27:53 +00:00
|
|
|
}
|
2020-04-30 13:00:33 +00:00
|
|
|
}
|
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
|
2020-04-13 12:56:41 +00:00
|
|
|
// CheckKeyedWitness checks hash of signature check contract with a given public
|
|
|
|
// key against current list of script hashes for verifying in the interop context.
|
2020-07-15 19:43:30 +00:00
|
|
|
func CheckKeyedWitness(ic *interop.Context, key *keys.PublicKey) (bool, error) {
|
|
|
|
return CheckHashedWitness(ic, key.GetScriptHash())
|
2020-04-13 12:56:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// CheckWitness checks witnesses.
|
2020-08-07 11:37:49 +00:00
|
|
|
func CheckWitness(ic *interop.Context) error {
|
2020-04-13 12:56:41 +00:00
|
|
|
var res bool
|
|
|
|
var err error
|
|
|
|
|
2020-08-07 11:37:49 +00:00
|
|
|
hashOrKey := ic.VM.Estack().Pop().Bytes()
|
2020-04-13 12:56:41 +00:00
|
|
|
hash, err := util.Uint160DecodeBytesBE(hashOrKey)
|
|
|
|
if err != nil {
|
|
|
|
var key *keys.PublicKey
|
2020-07-13 09:59:41 +00:00
|
|
|
key, err = keys.NewPublicKeyFromBytes(hashOrKey, elliptic.P256())
|
2020-04-13 12:56:41 +00:00
|
|
|
if err != nil {
|
|
|
|
return errors.New("parameter given is neither a key nor a hash")
|
|
|
|
}
|
2020-07-15 19:43:30 +00:00
|
|
|
res, err = CheckKeyedWitness(ic, key)
|
2020-04-13 12:56:41 +00:00
|
|
|
} else {
|
2020-07-15 19:43:30 +00:00
|
|
|
res, err = CheckHashedWitness(ic, hash)
|
2020-04-13 12:56:41 +00:00
|
|
|
}
|
|
|
|
if err != nil {
|
2020-08-06 14:44:08 +00:00
|
|
|
return fmt.Errorf("failed to check witness: %w", err)
|
2020-04-13 12:56:41 +00:00
|
|
|
}
|
2020-08-07 11:37:49 +00:00
|
|
|
ic.VM.Estack().PushVal(res)
|
2020-04-13 12:56:41 +00:00
|
|
|
return nil
|
|
|
|
}
|