github.com/machinefi/w3bstream@v1.6.5-rc9.0.20240426031326-b8c7c4876e72/pkg/types/types.go (about) 1 package types 2 3 import ( 4 "context" 5 "crypto/hmac" 6 "crypto/sha256" 7 "encoding/base64" 8 "encoding/json" 9 "fmt" 10 "net/http" 11 "slices" 12 "strconv" 13 "strings" 14 "time" 15 16 "github.com/blocto/solana-go-sdk/client" 17 "github.com/ethereum/go-ethereum/ethclient" 18 "github.com/pkg/errors" 19 "github.com/tidwall/gjson" 20 21 "github.com/machinefi/w3bstream/pkg/depends/base/types" 22 "github.com/machinefi/w3bstream/pkg/depends/kit/sqlx/datatypes" 23 "github.com/machinefi/w3bstream/pkg/depends/kit/validator/strfmt" 24 "github.com/machinefi/w3bstream/pkg/enums" 25 ) 26 27 type UploadConfig struct { 28 FilesizeLimitBytes int64 `env:""` 29 DiskReserveBytes int64 `env:""` 30 } 31 32 func (c *UploadConfig) SetDefault() { 33 if c.FilesizeLimitBytes == 0 { 34 c.FilesizeLimitBytes = 1024 * 1024 35 } 36 if c.DiskReserveBytes == 0 { 37 c.DiskReserveBytes = 20 * 1024 * 1024 38 } 39 } 40 41 type FileSystem struct { 42 Type enums.FileSystemMode `env:""` 43 } 44 45 func (f *FileSystem) SetDefault() { 46 if f.Type > enums.FILE_SYSTEM_MODE__S3 || f.Type <= 0 { 47 f.Type = enums.FILE_SYSTEM_MODE__LOCAL 48 } 49 } 50 51 type ETHClientConfig struct { 52 Endpoints string `env:""` 53 Clients map[uint32]*ethclient.Client `env:"-"` 54 } 55 56 func (c *ETHClientConfig) Init() error { 57 c.Clients = make(map[uint32]*ethclient.Client) 58 if !gjson.Valid(c.Endpoints) { 59 fmt.Println(c.Endpoints) 60 return errors.Errorf("faild to parse endpoints from environment") 61 } 62 for k, v := range gjson.Parse(c.Endpoints).Map() { 63 chainID, err := strconv.Atoi(k) 64 if err != nil { 65 continue 66 } 67 url := v.String() 68 cli, err := ethclient.Dial(url) 69 if err != nil { 70 return err 71 } 72 c.Clients[uint32(chainID)] = cli 73 } 74 return nil 75 } 76 77 type Chain struct { 78 ChainID uint64 `json:"chainID,omitempty"` 79 Name enums.ChainName `json:"name"` 80 Endpoint string `json:"endpoint"` 81 AABundlerEndpoint string `json:"aaBundlerEndpoint"` 82 AAPaymasterEndpoint string `json:"aaPaymasterEndpoint"` 83 AAEntryPointContractAddress string `json:"aaEntryPointContractAddress"` 84 AAAccountFactoryContractAddress string `json:"aaAccountFactoryContractAddress"` 85 } 86 87 func (c *Chain) IsSolana() bool { 88 return c.Name == enums.SOLANA_DEVNET || c.Name == enums.SOLANA_TESTNET || c.Name == enums.SOLANA_MAINNET_BETA 89 } 90 91 func (c *Chain) IsZKSync() bool { 92 return c.Name == enums.ZKSYNC_ERA_MAINNET || c.Name == enums.ZKSYNC_ERA_TESTNET 93 } 94 95 func (c *Chain) IsEth() bool { 96 return c.ChainID != 0 97 } 98 99 func (c *Chain) IsAASupported() bool { 100 return c.AABundlerEndpoint != "" && c.AAPaymasterEndpoint != "" && c.AAEntryPointContractAddress != "" && c.AAAccountFactoryContractAddress != "" 101 } 102 103 type ChainConfig struct { 104 Configs string `env:"" json:"-"` 105 Chains map[enums.ChainName]*Chain `env:"-" json:"-"` 106 ChainIDs map[uint64]*Chain `env:"-" json:"-"` 107 AAUserOpEndpoint string `env:"" json:"-"` 108 } 109 110 func (cc *ChainConfig) LivenessCheck() map[string]string { 111 m := map[string]string{} 112 113 for _, c := range cc.Chains { 114 key := c.Endpoint 115 if err := cc.chainLivenessCheck(c); err != nil { 116 m[key] = err.Error() 117 } else { 118 m[key] = "ok" 119 } 120 } 121 return m 122 } 123 124 func (c *ChainConfig) Init() { 125 cs := []*Chain{} 126 if c.Configs != "" { 127 if err := json.Unmarshal([]byte(c.Configs), &cs); err != nil { 128 panic(err) 129 } 130 } 131 132 cm := make(map[enums.ChainName]*Chain) 133 cidm := make(map[uint64]*Chain) 134 for _, c := range cs { 135 cm[c.Name] = c 136 if c.ChainID != 0 { 137 cidm[c.ChainID] = c 138 } 139 } 140 c.Chains = cm 141 c.ChainIDs = cidm 142 } 143 144 func (c *ChainConfig) GetChain(chainID uint64, chainName enums.ChainName) (*Chain, bool) { 145 r, ok := c.ChainIDs[chainID] 146 if ok { 147 return r, ok 148 } 149 r, ok = c.Chains[chainName] 150 return r, ok 151 } 152 153 func (c *ChainConfig) chainLivenessCheck(chain *Chain) error { 154 if chain.IsSolana() { 155 cli := client.NewClient(chain.Endpoint) 156 _, err := cli.GetLatestBlockhash(context.Background()) 157 return err 158 } else if chain.IsEth() { 159 cli, err := ethclient.Dial(chain.Endpoint) 160 if err != nil { 161 return err 162 } 163 defer cli.Close() 164 165 chainID, err := cli.ChainID(context.Background()) 166 if err != nil { 167 return err 168 } 169 if chainID.Uint64() != chain.ChainID { 170 return errors.Errorf("chainID mismatch, want %d, got %d", chain.ChainID, chainID.Uint64()) 171 } 172 } 173 return nil 174 } 175 176 // aliases from base/types 177 type ( 178 SFID = types.SFID 179 SFIDs = types.SFIDs 180 EthAddress = types.EthAddress 181 Timestamp = types.Timestamp 182 Initializer = types.Initializer 183 ValidatedInitializer = types.ValidatedInitializer 184 InitializerWith = types.InitializerWith 185 ValidatedInitializerWith = types.ValidatedInitializerWith 186 ) 187 188 type EthAddressWhiteList []string 189 190 func (v *EthAddressWhiteList) Init() { 191 lst := EthAddressWhiteList{} 192 for _, addr := range *v { 193 if err := strfmt.EthAddressValidator.Validate(addr); err == nil { 194 lst = append(lst, strings.ToLower(addr)) 195 } 196 } 197 *v = lst 198 } 199 200 func (v *EthAddressWhiteList) Validate(address string) bool { 201 if v == nil || len(*v) == 0 { 202 return true 203 } 204 for _, addr := range *v { 205 if addr == strings.ToLower(address) { 206 return true 207 } 208 } 209 return false 210 } 211 212 type StrategyResult struct { 213 ProjectName string `json:"projectName" db:"f_prj_name"` 214 AppletID types.SFID `json:"appletID" db:"f_app_id"` 215 AppletName string `json:"appletName" db:"f_app_name"` 216 InstanceID types.SFID `json:"instanceID" db:"f_ins_id"` 217 Handler string `json:"handler" db:"f_hdl"` 218 EventType string `json:"eventType" db:"f_evt"` 219 AutoCollect datatypes.Bool `json:"autoCollect" db:"f_auto_collect"` 220 } 221 222 type WasmDBConfig struct { 223 Endpoint types.Endpoint 224 MaxConnection int 225 PoolSize int 226 ConnMaxLifetime types.Duration 227 LazyInit bool 228 } 229 230 func (c *WasmDBConfig) SetDefault() { 231 if c.MaxConnection == 0 { 232 c.MaxConnection = 2 233 } 234 if c.PoolSize == 0 { 235 c.PoolSize = 2 236 } 237 if c.ConnMaxLifetime == 0 { 238 c.ConnMaxLifetime = *types.AsDuration(time.Second * 20) 239 } 240 } 241 242 type MetricsCenterConfig struct { 243 Endpoint string `env:""` 244 ClickHouseDSN string `env:""` 245 } 246 247 type RobotNotifierConfig struct { 248 Vendor string `env:""` // Vendor robot vendor eg: `Lark` `Wechat Work` `DingTalk` 249 Env string `env:""` // Env Service env, eg: dev-staging, prod 250 URL string `env:""` // URL webhook url 251 Secret string `env:""` // Secret message secret 252 PINs []string `env:""` // PINs pin someone 253 254 SignFn func(int64) (string, error) `env:"-"` 255 } 256 257 func (c *RobotNotifierConfig) IsZero() bool { return c == nil || c.URL == "" } 258 259 func (c *RobotNotifierConfig) Init() { 260 if c.Secret != "" { 261 c.SignFn = func(ts int64) (string, error) { 262 payload := fmt.Sprintf("%v", ts) + "\n" + c.Secret 263 264 var data []byte 265 h := hmac.New(sha256.New, []byte(payload)) 266 _, err := h.Write(data) 267 if err != nil { 268 return "", err 269 } 270 271 signature := base64.StdEncoding.EncodeToString(h.Sum(nil)) 272 return signature, nil 273 } 274 } 275 } 276 277 type Risc0Config struct { 278 Endpoint string 279 Websocket string 280 CreateProofPath string 281 } 282 283 func (r *Risc0Config) LivenessCheck() map[string]string { 284 m := map[string]string{} 285 286 _, err := http.NewRequest("GET", fmt.Sprintf("http://%s", r.Endpoint), nil) 287 if err != nil { 288 m[r.Endpoint] = err.Error() 289 } else { 290 m[r.Endpoint] = "ok" 291 } 292 293 return m 294 } 295 296 type ProjectFilter struct { 297 WhiteList []SFID 298 BlackList []SFID 299 } 300 301 func (f *ProjectFilter) Filter(id types.SFID) bool { 302 if len(f.WhiteList) > 0 { 303 return slices.Contains(f.WhiteList, id) 304 } 305 if len(f.BlackList) > 0 { 306 return !slices.Contains(f.BlackList, id) 307 } 308 return true 309 }