The declarative DB query is so much more than just the Contracts
object!
To be precise, it is:
- Contracts
- Functions
- Modifiers
- Instructions
- StateVariables
Each has many methods, and more importantly, you can combine them in the same query, filtering out unnecessary entities and improving the subsequent arbitrary logic part.
Take a look at this glide from the examples on the website:
from glider import *
def query():
instructions = (
Functions()
.without_properties([MethodProp.HAS_MODIFIERS])
.instructions()
.with_callee_function_name("selfdestruct")
.exec(100)
)
return instructions
It steps down from Functions
to Instructions
and uses both. In the first step, it gets rid of the functions with any modifiers, and in the second step, it queries all the instructions containing selfdestruct
call from the remaining functions.
Think of the combinations as layers where the contracts are the highest level and instructions are the lowest. You can jump between these layers however you like, one at a time. The final jump will determine what you'll get as a result.
All the possible transitions (pay attention to the directions):
flowchart TD
Contracts <--> Functions
Contracts -.-> StateVariables
Contracts -.-> Modifiers
Functions <--> Instructions
Functions <-.-> Modifiers
Modifiers <--> Instructions
Modifiers --> Contracts
*Weak dash links mean that you can't transit directly but need to loop and go through each single instance. For example, you can get StateVariables
from a Contract
instance. Similarly, you can get Modifiers
from a Function
and Functions
from a Modifier
.
E.g., if you add .functions()
to the glide above, you'll get List[Function]
, where each is without modifiers and contains selfdestruct
as one of their instructions.
from glider import *
def query():
functions = (
Functions()
.without_properties([MethodProp.HAS_MODIFIERS])
.instructions()
.with_callee_function_name("selfdestruct")
.functions()
.exec(100)
)
return functions
I have a few tips for you when it comes to the performance during combinations:
-
Try to avoid stepping up because it requires much more time (e.g.,
Functions
->Contracts
). -
If you need to step up, try to wrap your query like a sandwich, even if you don't need to use any methods from an upper layer. For example, if you need to do some logic with
Instructions
but want to get functions as a result, then:- Initiate the query with
Functions
- Step down to
Instructions
- Perform your operations
- Get back to
Functions
(like in the glide above)
This trick will cut out all instructions not in functions beforehand (like instructions from modifiers); thus, your operations will be performed on fewer instances.
- Initiate the query with
-
It's also useful to think about the size of the data you operate with and the complexity of operations. It's better to filter out as much as you can with simple operations before getting to complex ones like filtration by function signature.
Mix and experiment!