github.com/theQRL/go-zond@v0.1.1/signer/fourbyte/fourbyte.go (about) 1 // Copyright 2019 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 // Package fourbyte contains the 4byte database. 18 package fourbyte 19 20 import ( 21 _ "embed" 22 "encoding/hex" 23 "encoding/json" 24 "fmt" 25 "os" 26 ) 27 28 //go:embed 4byte.json 29 var embeddedJSON []byte 30 31 // Database is a 4byte database with the possibility of maintaining an immutable 32 // set (embedded) into the process and a mutable set (loaded and written to file). 33 type Database struct { 34 embedded map[string]string 35 custom map[string]string 36 customPath string 37 } 38 39 // newEmpty exists for testing purposes. 40 func newEmpty() *Database { 41 return &Database{ 42 embedded: make(map[string]string), 43 custom: make(map[string]string), 44 } 45 } 46 47 // New loads the standard signature database embedded in the package. 48 func New() (*Database, error) { 49 return NewWithFile("") 50 } 51 52 // NewFromFile loads signature database from file, and errors if the file is not 53 // valid JSON. The constructor does no other validation of contents. This method 54 // does not load the embedded 4byte database. 55 // 56 // The provided path will be used to write new values into if they are submitted 57 // via the API. 58 func NewFromFile(path string) (*Database, error) { 59 raw, err := os.Open(path) 60 if err != nil { 61 return nil, err 62 } 63 defer raw.Close() 64 65 db := newEmpty() 66 if err := json.NewDecoder(raw).Decode(&db.embedded); err != nil { 67 return nil, err 68 } 69 return db, nil 70 } 71 72 // NewWithFile loads both the standard signature database (embedded resource 73 // file) as well as a custom database. The latter will be used to write new 74 // values into if they are submitted via the API. 75 func NewWithFile(path string) (*Database, error) { 76 db := &Database{make(map[string]string), make(map[string]string), path} 77 db.customPath = path 78 79 if err := json.Unmarshal(embeddedJSON, &db.embedded); err != nil { 80 return nil, err 81 } 82 // Custom file may not exist. Will be created during save, if needed. 83 if _, err := os.Stat(path); err == nil { 84 var blob []byte 85 if blob, err = os.ReadFile(path); err != nil { 86 return nil, err 87 } 88 if err := json.Unmarshal(blob, &db.custom); err != nil { 89 return nil, err 90 } 91 } 92 return db, nil 93 } 94 95 // Size returns the number of 4byte entries in the embedded and custom datasets. 96 func (db *Database) Size() (int, int) { 97 return len(db.embedded), len(db.custom) 98 } 99 100 // Selector checks the given 4byte ID against the known ABI methods. 101 // 102 // This method does not validate the match, it's assumed the caller will do. 103 func (db *Database) Selector(id []byte) (string, error) { 104 if len(id) < 4 { 105 return "", fmt.Errorf("expected 4-byte id, got %d", len(id)) 106 } 107 sig := hex.EncodeToString(id[:4]) 108 if selector, exists := db.embedded[sig]; exists { 109 return selector, nil 110 } 111 if selector, exists := db.custom[sig]; exists { 112 return selector, nil 113 } 114 return "", fmt.Errorf("signature %v not found", sig) 115 } 116 117 // AddSelector inserts a new 4byte entry into the database. If custom database 118 // saving is enabled, the new dataset is also persisted to disk. 119 // 120 // Node, this method does _not_ validate the correctness of the data. It assumes 121 // the caller has already done so. 122 func (db *Database) AddSelector(selector string, data []byte) error { 123 // If the selector is already known, skip duplicating it 124 if len(data) < 4 { 125 return nil 126 } 127 if _, err := db.Selector(data[:4]); err == nil { 128 return nil 129 } 130 // Inject the custom selector into the database and persist if needed 131 db.custom[hex.EncodeToString(data[:4])] = selector 132 if db.customPath == "" { 133 return nil 134 } 135 blob, err := json.Marshal(db.custom) 136 if err != nil { 137 return err 138 } 139 return os.WriteFile(db.customPath, blob, 0600) 140 }