React Hooks are a very powerful tool to add interactivity and features to user interfaces. As your application grows, you will increasingly rely on hooks, composing simple ones into complex hooks, and, before you know it, end up with an unreadable, unmaintainable mess that rerenders 5 times a second for no apparent reason. In this article, I will show you some React Hooks antipatterns and how to avoid them if you want a clean, readable, and robust application.read more “Getting Out of Hook Hell: You Are Using React Hooks The Wrong Way”
Setting up the settings module in Django can be cumbersome for beginners. This module holds many properties that are vital to your application, and a minor error may be fatal. Moreover, you need to keep track of separate environments, such as local, dev, test, staging, production, and so on. In this short article, I will show you my approach to handling different environments in Django projects.read more “Easy Configuration Management in Django Projects”
Not long ago, I had to write a certain feature for my project. It involved parsing a mathematical expression from plaintext and evaluating it. This feature had to work with basic numerical expressions like
2 + 3, support context to use variables:
apples + 2 * oranges, and parentheses:
(2 + 3) - apples.
The obvious (and least appropriate) solution was to use
eval. This standard function takes a string and runs it, treating it like Python code. This is considered to be very unsafe:
eval an execute arbitrary code, which makes it a potential security risk, especially if the input comes from untrusted sources. Malicious users could inject harmful code that could lead to unintended consequences, such as executing system commands or accessing sensitive information.
In this article, I will walk you through my safe and extensible implementation using Python’s
React started its way in 2013 as a simple UI library, suitable for developing simple client-side web apps. It had evolved since then into a huge ecosystem of frameworks and communities. Many features were added as time passed, and one most notable is server-side rendering (SSR) in the form of NextJS and the like. However, this is about to change as React gets native support for server-side rendering in the form of Server Components.read more “Server Components in React: Exploring the Next Generation of Server-Side Rendering”
Many of us have experienced slow websites and laggy apps at least once while programming. These issues are inherent to the design of the systems we use each day: some operations take a (relatively) long time to complete. Transferring bytes over thousands of kilometres between you and the server, reading tiny magnetic fields on the spinning disk, and other such activities may take a moment. However, while your system is waiting for these resources it is essential to remain usable and responsive, and not waste precious CPU cycles. The concepts of concurrency and asynchronous programming were introduced to address these concerns.read more “A hands-on guide to concurrency in Python with asyncio”
Layer-2 blockchain solutions are protocols that are built on top of an existing blockchain, with the aim of increasing the scalability and performance of the underlying blockchain. These protocols often utilize off-chain transactions and smart contracts to reduce the burden on the main blockchain, allowing for faster and cheaper transactions. There are many different types of such solutions, including payment channels, rollups, side chains, and more. Examples of layer-2 solutions include the Lightning Network and the Optimism Network.
What are layer-2 blockchain solutions?
Layer-2 blockchain networks are designed to increase the scalability and efficiency of base blockchain networks. For example, the Lightning payment network lowers transaction fees and speeds up payments on the Bitcoin network. These layer-2 networks work by moving some of the transactions and data that would normally be processed on the blockchain itself off the chain and onto a separate layer. The implementation varies, such as building sidechains, state channels, or payment channels. By offloading some of the workloads from the main blockchain, layer-2 networks can help to reduce congestion and increase transaction speeds. Additionally, layer-2 networks can also be used to add new functionality to a blockchain, such as the ability to conduct atomic swaps or to support more complex smart contracts, like Echo.
What kinds of layer-2 blockchain solutions are there?
There are several different layer-2 networks in use today. They include channel-based (payment channels and state channels), rollups, sidechains, and commit chains.
The diagram above lists some main kinds of layer-2 blockchain solutions. I will talk about them briefly.
- Channels – these are designed to provide exchange or transfer of state (funds) between participants. Channels are established over a communication medium by locking the participants’ funds on the blockchain. Participants then exchange funds between themselves, and the channel is closed by committing new states (balances) to the main blockchain. An example of a payment channel solution is the Lightning network.
- Crosschains – these are independent blockchains, running in parallel to the main chain. They are designed to run faster than the main chain by exchanging transactions between different main blockchains. One prime example is Polkadot.
- Rollups – these are a kind of a sidechain solution. Transactions are processed in batches and compressed. Then they are bundled together for on-chain verification. Anyone can publish transactions using rollups, so to prevent fraud there are two strategies: optimistic rollups (all transactions are true unless disputed) and Zero-Knowledge rollups (all transactions are false unless proven). One example of an optimistic rollup system is the Optimism network.
- Commit chains – these were introduced to resolve some weaknesses of the channel solutions. It involves an operator that initializes and maintains a commit chain enforced by a smart contract. An example of a commit chain is Polygon.
What kinds of attacks are there?
Achieving scalability while preserving security is paramount to layer-2 networks. To foster mass adoption, layer-2 networks must be very hard to crack and exploit. Nevertheless, any and all systems are prone to error, and these networks are no exception. Below, I will list some of the most interesting and impactful vulnerabilities present in layer-2 networks.
Most of these vulnerabilities target payment networks and require good knowledge of how these networks work, particularly the concept of HTLC. To get up to speed, I suggest reading this and this first.
Wormhole attack targets payment channels such as Lightning and allows the attacker to profit by stealing the transaction fees from intermediaries.
In this type of attack, the attacker must control 2 nodes in the payment path, with one or more victim nodes between them. Then the first node gets the funds and transaction fees for the intermediaries, it can bypass the intermediaries, sending funds to the second attacking node and claiming the transaction rewards. This attack undermines the stability of the network as nodes will be less incentivized to participate in it.
To remediate this attack, Anonymous Multi-Hop Locks can be used.
This attack only focuses on DoS (denial-of-service) and does not by itself steal funds or turn a profit. It can target payment channels by initiating many payment transactions and locking the funds of all intermediaries for free. Then the attacker does not complete the transaction, waiting for the timeout to occur. This can be fixed by limiting the number of incoming channels, faster contract resolution, constant payment locktime, and implementing an incentive/punishment system for participant nodes.
Time dilation/eclipse attack
This is by far the most expensive and complex attack, and it can target many layer-2 solutions, not just payment channels. To pull off such an attack, an attacker needs to deceive the victim node’s clock, essentially making it go back in time.
The attacker uses multiple nodes that connect to the victim node until the victim exhausts its available connections. Once the victim is “surrounded”, the attacker controls (becoming a man-in-the-middle) what information the victim receives about transactions and new blocks. If the attacker delays the time so that the victim cannot dispute illegal transactions (by delaying time longer than the dispute timeout), the attacker can publish forged transactions concerning the victim’s funds and they will remain undisputed.
This kind of attack is very hard to counter effectively. One may watch for an abnormal routing failure rate as an indicator of the attack. You can also use watchtowers, that detect network discrepancies on the user’s behalf.
This relatively simple attack targets victims by locking their available funds and preventing them from participating in other transactions. Transactions in payment channels, such as Lightning, are atomic and will execute once all participants in the payment path have confirmed and locked the funds required to carry out the transactions. If an attacker sends a large payment
p to another attacking node,
p will be locked in all the intermediate nodes until the transaction is completed. Thus, the attacker only pays the price of the transaction fee to potentially block victim nodes from network participation.
By itself, this attack is not profitable, however, it can be used as a part of a larger attack, allowing the attacker to manipulate the transaction paths, blocking out the unfavourable ones and forcing transactions to take attacker-favoured paths.
To counterbalance lockdown attacks, the network may limit the length of payment routes and disallow loops in them, limiting the number of nodes that are blocked.
This kind of attack aims to disclose the balances of nodes participating in payment channels, like the Lightning network. An attacker creates a payment channel between two of its nodes through a victim node. Then the attacker tries to send some payments with increasing amounts. The victim node must lock the funds in order to carry out the transaction, and if it does not have enough funds, the transaction will fail. The attacker keeps sending payments until they start failing, at which point they can estimate the approximate balance of the intermediary node. To further improve this attack, use binary search for fewer payments.
To prevent such information leaks, a payment channel can set the maximum transaction amount to be lower than the balances of the participating nodes. Another way is to introduce randomly failing transactions, thus deceiving the attacker.
In conclusion, it is important to recognize that layer-2 networks inherently trade off security for efficiency. However, this does not mean that they are not secure enough for day-to-day transactions as long as proper research is conducted and best practices are followed. It is important to thoroughly evaluate the risks and potential vulnerabilities of any network before using it for valuable transactions. Do you agree with this assessment? Share your thoughts in the comments below.
This article is inspired by paper “A survey of Layer-two blockchain protocols” by Ankit Gangwal, Haripriya Ravali Gangavalli, and Apoorva Thirupathi. For more information about layer-2 networks, I suggest reading it here.
GitHub Actions is a tool that allows developers to automate workflows related to their GitHub repositories. With GitHub Actions, developers can build, test, and deploy their code directly from GitHub. While GitHub Actions can be very useful, they can also be difficult to debug when things go wrong. When an action fails, it can be challenging to figure out what went wrong and how to fix it, since they can only run on Github, and you end up sending mock commits one after another to iterate through bugfixes. Moreover, it can be costly, as Github Actions are billed per minute. In this post, I will talk about a tool called Act, which allows developers to run Github Actions locally on your machine.read more “Debug Github Actions locally with Act”
In software development, it is common to use remote and provisioned workers to execute code and run tasks. These workers can be located in remote data centers or cloud environments, and they can be accessed through a local integrated development environment (IDE) that connects to them over the internet. Using remote and provisioned workers can be beneficial because it allows developers to access powerful hardware and infrastructure without having to set it up locally. It can also be useful for teams that are distributed across different locations and need to collaborate on a project. Local IDEs can be used to write, debug, and deploy code to the remote workers, making it easy to work with and manage the codebase from a single interface. In this post, I will talk about setting up Jetbrains’ new IDE, Fleet, to work with a remote Linux machine.read more “Jetbrains Fleet: using remote workspaces for efficient development”
Version control systems are software tools that help developers track and manage changes to source code. There are several different version control systems available, each with its own set of features and capabilities. Some popular version control systems include Git, Mercurial, and Subversion. All of these version control systems are designed to help developers collaborate on projects, track changes to their code, and maintain a history of their work. In this post I will talk about a new player on the field, developed internally by Meta – Sapling.read more “Sapling by Meta: review and first impressions”
When working on a data science project in R, one often needs to write up a good-looking report, including some tables, formulas, and funny formatting. In this article, I will show you how to use Latex in RMarkdown to produce beautiful documents.read more “How to use Latex in RMarkdown”