Timelock pattern in Blockchain / Solidity - Time & Space Complexity
Start learning this pattern below
Jump into concepts and practice - no test required
When using the Timelock pattern in blockchain, it's important to know how the time to execute changes as more actions are queued.
We want to see how the number of queued transactions affects the time to process them.
Analyze the time complexity of the following code snippet.
function executeTransactions() public {
for (uint i = 0; i < queuedTransactions.length; i++) {
if (block.timestamp >= queuedTransactions[i].executeAfter) {
queuedTransactions[i].execute();
removeTransaction(i);
i--;
}
}
}
This code goes through all queued transactions and executes those whose time has come.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Looping through the list of queued transactions.
- How many times: Once for each transaction in the queue.
As the number of queued transactions grows, the time to check and execute them grows too.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 checks and possible executions |
| 100 | About 100 checks and possible executions |
| 1000 | About 1000 checks and possible executions |
Pattern observation: The work grows directly with the number of queued transactions.
Time Complexity: O(n)
This means the time to execute grows in a straight line as more transactions are queued.
[X] Wrong: "Executing transactions takes the same time no matter how many are queued."
[OK] Correct: Because the code checks each transaction one by one, more transactions mean more work and more time.
Understanding how loops over queued actions affect performance shows you can think about real blockchain contract costs and user experience.
"What if we stored transactions in a data structure that lets us quickly find only those ready to execute? How would the time complexity change?"
Practice
What is the main purpose of the Timelock pattern in blockchain smart contracts?
Solution
Step 1: Understand the Timelock pattern concept
The Timelock pattern is designed to delay actions in smart contracts until a set time has passed.Step 2: Identify the purpose of the delay
This delay helps protect users by preventing instant changes that could be harmful or unexpected.Final Answer:
To delay certain actions until a specific time has passed -> Option AQuick Check:
Timelock pattern = delay actions [OK]
- Thinking it speeds up transactions
- Confusing with encryption
- Assuming it lowers gas fees
Which of the following Solidity code snippets correctly enforces a timelock using block.timestamp?
function execute() public {
require(__________, "Too early to execute");
// action code
}Solution
Step 1: Understand the condition for timelock
The action should only execute if the current time is equal or after the unlock time.Step 2: Choose the correct comparison
Usingblock.timestamp >= unlockTimeensures the function runs only after the unlock time.Final Answer:
block.timestamp >= unlockTime -> Option AQuick Check:
Time check uses block.timestamp >= unlockTime [OK]
- Using < instead of >=
- Using block.number instead of block.timestamp
- Using unrelated block properties
What will be the output of the following Solidity function call if block.timestamp is 1650000000 and unlockTime is 1650000100?
function canExecute() public view returns (bool) {
return block.timestamp >= unlockTime;
}Solution
Step 1: Compare block.timestamp and unlockTime values
Given block.timestamp = 1650000000 and unlockTime = 1650000100, block.timestamp is less than unlockTime.Step 2: Evaluate the return statement
The expressionblock.timestamp >= unlockTimeevaluates to false.Final Answer:
false -> Option DQuick Check:
1650000000 >= 1650000100 = false [OK]
- Assuming >= means true when timestamp is smaller
- Confusing block.timestamp with block.number
- Expecting errors instead of boolean
Identify the error in this Solidity timelock function and choose the fix:
uint256 public unlockTime;
function execute() public {
require(block.timestamp > unlockTime, "Too early");
// perform action
}Solution
Step 1: Analyze the require condition
The conditionblock.timestamp > unlockTimedisallows execution exactly at unlockTime.Step 2: Adjust condition to allow execution at unlockTime
Changing toblock.timestamp >= unlockTimeallows execution starting from unlockTime.Final Answer:
Change block.timestamp > unlockTime to block.timestamp >= unlockTime -> Option BQuick Check:
Use >= to include unlockTime moment [OK]
- Using > excludes unlockTime moment
- Removing require loses protection
- Using block.number causes wrong timing
You want to create a timelock contract that allows an admin to schedule a withdrawal only after 1 day from scheduling. Which approach correctly implements this?
contract Timelock {
address public admin;
uint256 public unlockTime;
constructor() {
admin = msg.sender;
}
function scheduleWithdrawal() public {
require(msg.sender == admin, "Not admin");
unlockTime = block.timestamp + 86400; // 1 day
}
function withdraw() public {
require(msg.sender == admin, "Not admin");
require(block.timestamp >= unlockTime, "Too early");
// withdrawal logic
}
}Solution
Step 1: Check scheduling sets unlockTime correctly
ThescheduleWithdrawalfunction setsunlockTimeto current time plus 86400 seconds (1 day).Step 2: Verify withdraw enforces timelock
Thewithdrawfunction requires current time to be at or afterunlockTime, enforcing the delay.Final Answer:
Correctly enforces 1-day delay before withdrawal -> Option CQuick Check:
UnlockTime = now + 1 day, withdraw requires >= unlockTime [OK]
- Not adding delay in schedule function
- Using > instead of >= in withdraw
- Not restricting functions to admin
