github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/evm/keeper/querier.go (about) 1 package keeper 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "strconv" 7 8 ethcmn "github.com/ethereum/go-ethereum/common" 9 "github.com/ethereum/go-ethereum/crypto" 10 apptypes "github.com/fibonacci-chain/fbc/app/types" 11 "github.com/fibonacci-chain/fbc/app/utils" 12 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/codec" 13 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/mpt" 14 sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types" 15 sdkerrors "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/errors" 16 abci "github.com/fibonacci-chain/fbc/libs/tendermint/abci/types" 17 "github.com/fibonacci-chain/fbc/x/evm/types" 18 ) 19 20 // NewQuerier is the module level router for state queries 21 func NewQuerier(keeper Keeper) sdk.Querier { 22 return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) { 23 if len(path) < 1 { 24 return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, 25 "Insufficient parameters, at least 1 parameter is required") 26 } 27 28 switch path[0] { 29 case types.QueryBalance: 30 return queryBalance(ctx, path, keeper) 31 case types.QueryBlockNumber: 32 return queryBlockNumber(ctx, keeper) 33 case types.QueryStorage: 34 return queryStorage(ctx, path, keeper) 35 case types.QueryStorageProof: 36 return queryStorageProof(ctx, path, keeper, req.Height) 37 case types.QueryStorageRoot: 38 return queryStorageRootHash(ctx, path, keeper, req.Height) 39 case types.QueryStorageByKey: 40 return queryStorageByKey(ctx, path, keeper) 41 case types.QueryCode: 42 return queryCode(ctx, path, keeper) 43 case types.QueryCodeByHash: 44 return queryCodeByHash(ctx, path, keeper) 45 case types.QueryHashToHeight: 46 return queryHashToHeight(ctx, path, keeper) 47 case types.QueryBloom: 48 return queryBlockBloom(ctx, path, keeper) 49 case types.QueryAccount: 50 return queryAccount(ctx, path, keeper) 51 case types.QueryExportAccount: 52 return queryExportAccount(ctx, path, keeper) 53 case types.QueryParameters: 54 return queryParams(ctx, keeper) 55 case types.QueryHeightToHash: 56 return queryHeightToHash(ctx, path, keeper) 57 case types.QuerySection: 58 return querySection(ctx, path, keeper) 59 case types.QueryContractDeploymentWhitelist: 60 return queryContractDeploymentWhitelist(ctx, keeper) 61 case types.QueryContractBlockedList: 62 return queryContractBlockedList(ctx, keeper) 63 case types.QueryContractMethodBlockedList: 64 return queryContractMethodBlockedList(ctx, keeper) 65 case types.QuerySysContractAddress: 66 return querySysContractAddress(ctx, keeper) 67 default: 68 return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "unknown query endpoint") 69 } 70 } 71 } 72 73 func queryContractMethodBlockedList(ctx sdk.Context, keeper Keeper) (res []byte, err sdk.Error) { 74 blockedList := types.CreateEmptyCommitStateDB(keeper.GeneratePureCSDBParams(), ctx).GetContractMethodBlockedList() 75 res, errUnmarshal := codec.MarshalJSONIndent(types.ModuleCdc, blockedList) 76 if errUnmarshal != nil { 77 return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to marshal result to JSON", errUnmarshal.Error())) 78 } 79 80 return res, nil 81 } 82 83 func queryContractBlockedList(ctx sdk.Context, keeper Keeper) (res []byte, err sdk.Error) { 84 blockedList := types.CreateEmptyCommitStateDB(keeper.GeneratePureCSDBParams(), ctx).GetContractBlockedList() 85 res, errUnmarshal := codec.MarshalJSONIndent(types.ModuleCdc, blockedList) 86 if errUnmarshal != nil { 87 return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to marshal result to JSON", errUnmarshal.Error())) 88 } 89 90 return res, nil 91 } 92 93 func queryContractDeploymentWhitelist(ctx sdk.Context, keeper Keeper) (res []byte, err sdk.Error) { 94 whitelist := types.CreateEmptyCommitStateDB(keeper.GeneratePureCSDBParams(), ctx).GetContractDeploymentWhitelist() 95 res, errUnmarshal := codec.MarshalJSONIndent(types.ModuleCdc, whitelist) 96 if errUnmarshal != nil { 97 return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to marshal result to JSON", errUnmarshal.Error())) 98 } 99 100 return res, nil 101 } 102 103 func queryBalance(ctx sdk.Context, path []string, keeper Keeper) ([]byte, error) { 104 if len(path) < 2 { 105 return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, 106 "Insufficient parameters, at least 2 parameters is required") 107 } 108 109 addr := ethcmn.HexToAddress(path[1]) 110 balance := keeper.GetBalance(ctx, addr) 111 balanceStr, err := utils.MarshalBigInt(balance) 112 if err != nil { 113 return nil, err 114 } 115 116 res := types.QueryResBalance{Balance: balanceStr} 117 bz, err := codec.MarshalJSONIndent(keeper.cdc, res) 118 if err != nil { 119 return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) 120 } 121 122 return bz, nil 123 } 124 125 func queryBlockNumber(ctx sdk.Context, keeper Keeper) ([]byte, error) { 126 num := ctx.BlockHeight() 127 bnRes := types.QueryResBlockNumber{Number: num} 128 bz, err := codec.MarshalJSONIndent(keeper.cdc, bnRes) 129 if err != nil { 130 return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) 131 } 132 133 return bz, nil 134 } 135 136 func queryStorage(ctx sdk.Context, path []string, keeper Keeper) ([]byte, error) { 137 if len(path) < 3 { 138 return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, 139 "Insufficient parameters, at least 3 parameters is required") 140 } 141 142 addr := ethcmn.HexToAddress(path[1]) 143 key := ethcmn.HexToHash(path[2]) 144 val := keeper.GetState(ctx, addr, key) 145 res := types.QueryResStorage{Value: val.Bytes()} 146 bz, err := codec.MarshalJSONIndent(keeper.cdc, res) 147 if err != nil { 148 return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) 149 } 150 return bz, nil 151 } 152 153 func queryStorageProof(ctx sdk.Context, path []string, keeper Keeper, height int64) ([]byte, error) { 154 if len(path) < 3 { 155 return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, 156 "Insufficient parameters, at least 3 parameters is required") 157 } 158 159 addr := ethcmn.HexToAddress(path[1]) 160 storageRootHash, err := queryStorageRootBytesInHeight(keeper, addr, height) 161 if err != nil { 162 return nil, fmt.Errorf("get %s storage root hash failed: %s", addr, err.Error()) 163 } 164 165 // check if storageRootHash is empty 166 var res types.QueryResStorageProof 167 if storageRootHash == nil { 168 res = types.QueryResStorageProof{Value: []byte{}, Proof: [][]byte{}} 169 } else { 170 // open storage trie base on storage root hash 171 storageTrie, err := keeper.db.OpenTrie(ethcmn.BytesToHash(storageRootHash)) 172 if err != nil { 173 return nil, fmt.Errorf("open %s storage trie failed: %s", addr, err.Error()) 174 } 175 176 // append key 177 key := ethcmn.HexToHash(path[2]) 178 val, err := storageTrie.TryGet(crypto.Keccak256(append(addr.Bytes(), key.Bytes()...))) 179 if err != nil { 180 return nil, fmt.Errorf("get %s storage in location %s failed: %s", addr, key, err.Error()) 181 } 182 // check if value is found 183 if val == nil { 184 res = types.QueryResStorageProof{Value: []byte{}, Proof: [][]byte{}} 185 } else { 186 var proof mpt.ProofList 187 if err = storageTrie.Prove(crypto.Keccak256(key.Bytes()), 0, &proof); err != nil { 188 return nil, fmt.Errorf("trie generate proof failed: %s", err.Error()) 189 } 190 res = types.QueryResStorageProof{Value: val, Proof: proof} 191 } 192 } 193 194 // marshal result 195 bz, err := codec.MarshalJSONIndent(keeper.cdc, res) 196 if err != nil { 197 return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) 198 } 199 return bz, nil 200 } 201 202 func queryStorageByKey(ctx sdk.Context, path []string, keeper Keeper) ([]byte, error) { 203 if len(path) < 3 { 204 return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, 205 "Insufficient parameters, at least 3 parameters is required") 206 } 207 208 addr := ethcmn.HexToAddress(path[1]) 209 key := ethcmn.HexToHash(path[2]) 210 val := keeper.GetStateByKey(ctx, addr, key) 211 res := types.QueryResStorage{Value: val.Bytes()} 212 bz, err := codec.MarshalJSONIndent(keeper.cdc, res) 213 if err != nil { 214 return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) 215 } 216 return bz, nil 217 } 218 219 func queryStorageRootHash(ctx sdk.Context, path []string, keeper Keeper, height int64) ([]byte, error) { 220 if len(path) < 2 { 221 return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, 222 "Insufficient parameters, at least 1 parameters is required") 223 } 224 225 addr := ethcmn.HexToAddress(path[1]) 226 storageRootHash, err := queryStorageRootBytesInHeight(keeper, addr, height) 227 if err != nil { 228 return nil, fmt.Errorf("get %s storage root hash failed: %s", addr, err.Error()) 229 } 230 231 if storageRootHash == nil { 232 return mpt.EmptyRootHashBytes, nil 233 } else { 234 return storageRootHash, nil 235 } 236 } 237 238 func queryStorageRootBytesInHeight(keeper Keeper, addr ethcmn.Address, height int64) ([]byte, error) { 239 // query evm tire root hash based on height 240 evmRootHash := keeper.GetMptRootHash(uint64(height)) 241 if evmRootHash == mpt.NilHash { 242 return nil, fmt.Errorf("header %d not found", height) 243 } 244 245 // query storage root hash base on address in evmTrie 246 evmTrie, err := keeper.db.OpenTrie(evmRootHash) 247 if err != nil { 248 return nil, fmt.Errorf("open evm trie failed: %s", err.Error()) 249 } 250 storageRootHash, err := evmTrie.TryGet(addr.Bytes()) 251 if err != nil { 252 return nil, fmt.Errorf("get %s storage root hash failed: %s", addr, err.Error()) 253 } 254 return storageRootHash, nil 255 } 256 257 func queryCode(ctx sdk.Context, path []string, keeper Keeper) ([]byte, error) { 258 if len(path) < 2 { 259 return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, 260 "Insufficient parameters, at least 2 parameters is required") 261 } 262 263 addr := ethcmn.HexToAddress(path[1]) 264 so := keeper.GetOrNewStateObject(ctx, addr) 265 code := keeper.GetCodeByHash(ctx, ethcmn.BytesToHash(so.CodeHash())) 266 res := types.QueryResCode{Code: code} 267 bz, err := codec.MarshalJSONIndent(keeper.cdc, res) 268 if err != nil { 269 return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) 270 } 271 272 return bz, nil 273 } 274 275 func queryCodeByHash(ctx sdk.Context, path []string, keeper Keeper) ([]byte, error) { 276 if len(path) < 2 { 277 return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, 278 "Insufficient parameters, at least 2 parameters is required") 279 } 280 281 hash := ethcmn.HexToHash(path[1]) 282 code := keeper.GetCodeByHash(ctx, hash) 283 res := types.QueryResCode{Code: code} 284 bz, err := codec.MarshalJSONIndent(keeper.cdc, res) 285 if err != nil { 286 return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) 287 } 288 289 return bz, nil 290 } 291 292 func queryHashToHeight(ctx sdk.Context, path []string, keeper Keeper) ([]byte, error) { 293 if len(path) < 2 { 294 return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, 295 "Insufficient parameters, at least 2 parameters is required") 296 } 297 298 blockHash := ethcmn.HexToHash(path[1]) 299 blockNumber, found := keeper.GetBlockHeight(ctx, blockHash) 300 if !found { 301 return []byte{}, sdkerrors.Wrap(types.ErrKeyNotFound, fmt.Sprintf("block height not found for hash %s", path[1])) 302 } 303 304 res := types.QueryResBlockNumber{Number: blockNumber} 305 bz, err := codec.MarshalJSONIndent(keeper.cdc, res) 306 if err != nil { 307 return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) 308 } 309 310 return bz, nil 311 } 312 313 func queryBlockBloom(ctx sdk.Context, path []string, keeper Keeper) ([]byte, error) { 314 if len(path) < 2 { 315 return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, 316 "Insufficient parameters, at least 2 parameters is required") 317 } 318 319 num, err := strconv.ParseInt(path[1], 10, 64) 320 if err != nil { 321 return nil, sdkerrors.Wrap(types.ErrStrConvertFailed, fmt.Sprintf("could not unmarshal block height: %s", err)) 322 } 323 324 copyCtx := ctx 325 copyCtx.SetBlockHeight(num) 326 bloom := keeper.GetBlockBloom(copyCtx, num) 327 res := types.QueryBloomFilter{Bloom: bloom} 328 bz, err := codec.MarshalJSONIndent(keeper.cdc, res) 329 if err != nil { 330 return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) 331 } 332 333 return bz, nil 334 } 335 336 func queryAccount(ctx sdk.Context, path []string, keeper Keeper) ([]byte, error) { 337 if len(path) < 2 { 338 return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, 339 "Insufficient parameters, at least 2 parameters is required") 340 } 341 342 addr := ethcmn.HexToAddress(path[1]) 343 res, err := resolveEthAccount(ctx, keeper, addr) 344 if err != nil { 345 return nil, err 346 } 347 bz, err := codec.MarshalJSONIndent(keeper.cdc, res) 348 if err != nil { 349 return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) 350 } 351 return bz, nil 352 } 353 354 func resolveEthAccount(ctx sdk.Context, k Keeper, addr ethcmn.Address) (*types.QueryResAccount, error) { 355 codeHash := mpt.EmptyCodeHashBytes 356 account := k.accountKeeper.GetAccount(ctx, addr.Bytes()) 357 if account == nil { 358 return &types.QueryResAccount{Nonce: uint64(0), CodeHash: codeHash, Balance: "0x0"}, nil 359 } 360 ethAccount := account.(*apptypes.EthAccount) 361 if ethAccount == nil { 362 return &types.QueryResAccount{Nonce: uint64(0), CodeHash: codeHash, Balance: "0x0"}, nil 363 } 364 365 // get balance 366 balance := ethAccount.Balance(sdk.DefaultBondDenom).BigInt() 367 if balance == nil { 368 balance = sdk.ZeroInt().BigInt() 369 } 370 balanceStr, err := utils.MarshalBigInt(balance) 371 if err != nil { 372 return nil, err 373 } 374 375 // get codeHash 376 if ethAccount.CodeHash != nil { 377 codeHash = ethAccount.CodeHash 378 } 379 380 //return 381 return &types.QueryResAccount{ 382 Balance: balanceStr, 383 CodeHash: codeHash, 384 Nonce: ethAccount.Sequence, 385 }, nil 386 } 387 388 func queryExportAccount(ctx sdk.Context, path []string, keeper Keeper) ([]byte, error) { 389 if len(path) < 2 { 390 return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, 391 "Insufficient parameters, at least 2 parameters is required") 392 } 393 394 hexAddress := path[1] 395 addr := ethcmn.HexToAddress(hexAddress) 396 397 var storage types.Storage 398 err := keeper.ForEachStorage(ctx, addr, func(key, value ethcmn.Hash) bool { 399 storage = append(storage, types.NewState(key, value)) 400 return false 401 }) 402 if err != nil { 403 return nil, err 404 } 405 406 res := types.GenesisAccount{ 407 Address: hexAddress, 408 Code: keeper.GetCode(ctx, addr), 409 Storage: storage, 410 } 411 412 // TODO: codec.MarshalJSONIndent doesn't call the String() method of types properly 413 bz, err := json.MarshalIndent(res, "", "\t") 414 if err != nil { 415 return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) 416 } 417 418 return bz, nil 419 } 420 421 func queryParams(ctx sdk.Context, keeper Keeper) (res []byte, err sdk.Error) { 422 params := keeper.GetParams(ctx) 423 res, errUnmarshal := codec.MarshalJSONIndent(types.ModuleCdc, params) 424 if errUnmarshal != nil { 425 return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to marshal result to JSON", errUnmarshal.Error())) 426 } 427 return res, nil 428 } 429 430 func queryHeightToHash(ctx sdk.Context, path []string, keeper Keeper) ([]byte, error) { 431 if len(path) < 2 { 432 return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, 433 "Insufficient parameters, at least 2 parameters is required") 434 } 435 436 height, err := strconv.Atoi(path[1]) 437 if err != nil { 438 return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, 439 "Insufficient parameters, params[1] convert to int failed") 440 } 441 hash := keeper.GetHeightHash(ctx, uint64(height)) 442 443 return hash.Bytes(), nil 444 } 445 446 func querySection(ctx sdk.Context, path []string, keeper Keeper) ([]byte, error) { 447 if !types.GetEnableBloomFilter() { 448 return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, 449 "disable bloom filter") 450 } 451 452 if len(path) != 1 { 453 return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, 454 "wrong parameters, need no parameters") 455 } 456 457 res, err := json.Marshal(types.GetIndexer().StoredSection()) 458 if err != nil { 459 return nil, err 460 } 461 462 return res, nil 463 }