github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/core/interop/runtime/witness.go (about) 1 package runtime 2 3 import ( 4 "crypto/elliptic" 5 "errors" 6 "fmt" 7 8 "github.com/nspcc-dev/neo-go/pkg/core/interop" 9 "github.com/nspcc-dev/neo-go/pkg/core/transaction" 10 "github.com/nspcc-dev/neo-go/pkg/crypto/keys" 11 "github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag" 12 "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" 13 "github.com/nspcc-dev/neo-go/pkg/util" 14 "github.com/nspcc-dev/neo-go/pkg/vm" 15 "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" 16 ) 17 18 // CheckHashedWitness checks the given hash against the current list of script hashes 19 // for verifying in the interop context. 20 func CheckHashedWitness(ic *interop.Context, hash util.Uint160) (bool, error) { 21 callingSH := ic.VM.GetCallingScriptHash() 22 if !callingSH.Equals(util.Uint160{}) && hash.Equals(callingSH) { 23 return true, nil 24 } 25 return checkScope(ic, hash) 26 } 27 28 type scopeContext struct { 29 *vm.VM 30 ic *interop.Context 31 } 32 33 func getContractGroups(v *vm.VM, ic *interop.Context, h util.Uint160) (manifest.Groups, error) { 34 if !v.Context().GetCallFlags().Has(callflag.ReadStates) { 35 return nil, errors.New("missing ReadStates call flag") 36 } 37 cs, err := ic.GetContract(h) 38 if err != nil { 39 return nil, nil // It's OK to not have the contract. 40 } 41 return manifest.Groups(cs.Manifest.Groups), nil 42 } 43 44 func (sc scopeContext) IsCalledByEntry() bool { 45 return sc.VM.Context().IsCalledByEntry() 46 } 47 48 func (sc scopeContext) checkScriptGroups(h util.Uint160, k *keys.PublicKey) (bool, error) { 49 groups, err := getContractGroups(sc.VM, sc.ic, h) 50 if err != nil { 51 return false, err 52 } 53 return groups.Contains(k), nil 54 } 55 56 func (sc scopeContext) CallingScriptHasGroup(k *keys.PublicKey) (bool, error) { 57 return sc.checkScriptGroups(sc.GetCallingScriptHash(), k) 58 } 59 60 func (sc scopeContext) CurrentScriptHasGroup(k *keys.PublicKey) (bool, error) { 61 return sc.checkScriptGroups(sc.GetCurrentScriptHash(), k) 62 } 63 64 func checkScope(ic *interop.Context, hash util.Uint160) (bool, error) { 65 signers := ic.Signers() 66 if len(signers) == 0 { 67 return false, errors.New("no valid signers") 68 } 69 for i := range signers { 70 c := &signers[i] 71 if c.Account == hash { 72 if c.Scopes == transaction.Global { 73 return true, nil 74 } 75 if c.Scopes&transaction.CalledByEntry != 0 { 76 if ic.VM.Context().IsCalledByEntry() { 77 return true, nil 78 } 79 } 80 if c.Scopes&transaction.CustomContracts != 0 { 81 currentScriptHash := ic.VM.GetCurrentScriptHash() 82 for _, allowedContract := range c.AllowedContracts { 83 if allowedContract == currentScriptHash { 84 return true, nil 85 } 86 } 87 } 88 if c.Scopes&transaction.CustomGroups != 0 { 89 groups, err := getContractGroups(ic.VM, ic, ic.VM.GetCurrentScriptHash()) 90 if err != nil { 91 return false, err 92 } 93 // check if the current group is the required one 94 for _, allowedGroup := range c.AllowedGroups { 95 if groups.Contains(allowedGroup) { 96 return true, nil 97 } 98 } 99 } 100 if c.Scopes&transaction.Rules != 0 { 101 ctx := scopeContext{ic.VM, ic} 102 for _, r := range c.Rules { 103 res, err := r.Condition.Match(ctx) 104 if err != nil { 105 return false, err 106 } 107 if res { 108 return r.Action == transaction.WitnessAllow, nil 109 } 110 } 111 } 112 return false, nil 113 } 114 } 115 return false, nil 116 } 117 118 // CheckKeyedWitness checks the hash of the signature check contract with the given public 119 // key against the current list of script hashes for verifying in the interop context. 120 func CheckKeyedWitness(ic *interop.Context, key *keys.PublicKey) (bool, error) { 121 return CheckHashedWitness(ic, key.GetScriptHash()) 122 } 123 124 // CheckWitness checks witnesses. 125 func CheckWitness(ic *interop.Context) error { 126 var res bool 127 var err error 128 129 hashOrKey := ic.VM.Estack().Pop().Bytes() 130 hash, err := util.Uint160DecodeBytesBE(hashOrKey) 131 if err != nil { 132 var key *keys.PublicKey 133 key, err = keys.NewPublicKeyFromBytes(hashOrKey, elliptic.P256()) 134 if err != nil { 135 return errors.New("parameter given is neither a key nor a hash") 136 } 137 res, err = CheckKeyedWitness(ic, key) 138 } else { 139 res, err = CheckHashedWitness(ic, hash) 140 } 141 if err != nil { 142 return fmt.Errorf("failed to check witness: %w", err) 143 } 144 ic.VM.Estack().PushItem(stackitem.Bool(res)) 145 return nil 146 }