github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/core/transaction/witness_scope.go (about) 1 package transaction 2 3 //go:generate stringer -type=WitnessScope -linecomment -output=witness_scope_string.go 4 import ( 5 "encoding/json" 6 "errors" 7 "fmt" 8 "strings" 9 ) 10 11 // WitnessScope represents set of witness flags for Transaction signer. 12 type WitnessScope byte 13 14 const ( 15 // None specifies that no contract was witnessed. Only sign the transaction. 16 None WitnessScope = 0 17 // CalledByEntry witness is only valid in entry script and ones directly called by it. 18 // No params is needed, as the witness/permission/signature given on first invocation will 19 // automatically expire if entering deeper internal invokes. This can be default safe 20 // choice for native NEO/GAS (previously used on Neo 2 as "attach" mode). 21 CalledByEntry WitnessScope = 0x01 22 // CustomContracts define custom hash for contract-specific. 23 CustomContracts WitnessScope = 0x10 24 // CustomGroups define custom pubkey for group members. 25 CustomGroups WitnessScope = 0x20 26 // Rules is a set of conditions with boolean operators. 27 Rules WitnessScope = 0x40 // WitnessRules 28 // Global allows this witness in all contexts (default Neo2 behavior). 29 // This cannot be combined with other flags. 30 Global WitnessScope = 0x80 31 ) 32 33 // ScopesFromByte converts byte to a set of WitnessScopes and performs validity 34 // check. 35 func ScopesFromByte(b byte) (WitnessScope, error) { 36 var res = WitnessScope(b) 37 if (res&Global != 0) && (res&(None|CalledByEntry|CustomContracts|CustomGroups|Rules) != 0) { 38 return 0, errors.New("Global scope can not be combined with other scopes") 39 } 40 if res&^(None|CalledByEntry|CustomContracts|CustomGroups|Rules|Global) != 0 { 41 return 0, fmt.Errorf("invalid scope %d", res) 42 } 43 return res, nil 44 } 45 46 // ScopesFromString converts string of comma-separated scopes to a set of scopes 47 // (case-sensitive). String can combine several scopes, e.g. be any of: 'Global', 48 // 'CalledByEntry,CustomGroups' etc. In case of an empty string an error will be 49 // returned. 50 func ScopesFromString(s string) (WitnessScope, error) { 51 var result WitnessScope 52 scopes := strings.Split(s, ",") 53 for i, scope := range scopes { 54 scopes[i] = strings.TrimSpace(scope) 55 } 56 dict := map[string]WitnessScope{ 57 Global.String(): Global, 58 CalledByEntry.String(): CalledByEntry, 59 CustomContracts.String(): CustomContracts, 60 CustomGroups.String(): CustomGroups, 61 Rules.String(): Rules, 62 None.String(): None, 63 } 64 var isGlobal bool 65 for _, scopeStr := range scopes { 66 scope, ok := dict[scopeStr] 67 if !ok { 68 return result, fmt.Errorf("invalid witness scope: %v", scopeStr) 69 } 70 if isGlobal && !(scope == Global) { 71 return result, errors.New("Global scope can not be combined with other scopes") 72 } 73 result |= scope 74 if scope == Global { 75 isGlobal = true 76 } 77 } 78 return result, nil 79 } 80 81 func appendScopeString(str string, scopes WitnessScope, scope WitnessScope) string { 82 if scopes&scope != 0 { 83 if len(str) != 0 { 84 str += ", " 85 } 86 str += scope.String() 87 } 88 return str 89 } 90 91 // scopesToString converts witness scope to it's string representation. It uses 92 // `, ` to separate scope names. 93 func scopesToString(scopes WitnessScope) string { 94 if scopes&Global != 0 || scopes == None { 95 return scopes.String() 96 } 97 var res string 98 res = appendScopeString(res, scopes, CalledByEntry) 99 res = appendScopeString(res, scopes, CustomContracts) 100 res = appendScopeString(res, scopes, CustomGroups) 101 res = appendScopeString(res, scopes, Rules) 102 return res 103 } 104 105 // MarshalJSON implements the json.Marshaler interface. 106 func (s WitnessScope) MarshalJSON() ([]byte, error) { 107 return []byte(`"` + scopesToString(s) + `"`), nil 108 } 109 110 // UnmarshalJSON implements the json.Unmarshaler interface. 111 func (s *WitnessScope) UnmarshalJSON(data []byte) error { 112 var js string 113 if err := json.Unmarshal(data, &js); err != nil { 114 return err 115 } 116 scopes, err := ScopesFromString(js) 117 if err != nil { 118 return err 119 } 120 *s = scopes 121 return nil 122 }