Use Case: Decentralized User Information Management on Ethereum using Smart Contracts

As I continue my journey into the blockchain, specifically with Ethereum and its programming language Solidity, I’ve come across an interesting use case highlighting this technology’s unique value. In one of the practical exercises, we explored an example where only blockchain technology can provide the solution due to its inherent advantages, such as decentralization, security, and transparency.

This use case involves creating a smart contract on Ethereum to manage user information in a fully decentralized manner. The contract allows for two types of datasets: basic data (like simple sizes and preferences) and complete data (containing more detailed user information). The system’s logic relies on secure transactions and executing contracts without intermediaries, utilizing Ethereum’s distributed infrastructure.

How Does It Work?

Using an application connected to the blockchain through Web3, The shop can query the information stored in the smart contract by providing their Ethereum address. This query retrieves the user’s personalized data. Then, the products are displayed and adjusted within the interface according to the preferences.

Additionally, the user can update their data or change their password at any time, with all updates processed through secure transactions and permanently recorded on the blockchain.

This example not only demonstrates how Ethereum and Solidity can be used to create applications that ensure the integrity and privacy of user data, but it also highlights the value of decentralized technology in real-world applications, where the need for intermediaries or central servers is eliminated.

The use of blockchain is crucial in this context, providing benefits that would be difficult to achieve with traditional systems, such as:

  • Data immutability: Once information is stored on the blockchain, altering it without the network’s consensus is extremely difficult.
  • User control over personal data: Instead of relying on a central entity to manage the information, the user has complete control over what is stored and updated in the smart contract.
  • Inherent security: Blockchain technology provides a secure environment for executing transactions and storing data, making fraud or tampering attempts virtually impossible.

This use case clearly illustrates that, in certain scenarios, traditional solutions are not sufficient, and technologies like Ethereum play a vital role in providing a more robust and trustworthy platform.

Next week, I’ll provide more technical details and a repository with an example of the solution (the same example as I have in my course; it’s not something new):

  • A contract written in Solidity and deployed on the Ethereal blockchain.
  • Test suite to validate that our contract works.
  • To ensure we can compile and use an up-to-date contract, we make a web server (contract server) that compiles and serves the compiled contract to the rest of the solution.
  • As an example of user interaction, we will create a simple Web Application to show how we can deploy the contract from a web application, modify the values ​​, and return them to the blockchain.

Here the contract, as you can see, is very simple code (simple example, too):

Nuria

Fail Fast: Object.requireNonNull(param) in Your Code?

When developing in Java, you might encounter the utility method Object.requireNonNull(param). At first, it might seem redundant because if param is null, a NullPointerException (NPE) will eventually be thrown when you attempt to use it. However, using Object.requireNonNull(param) serves a critical purpose: it ensures you catch the NullPointerException as early as possible and in the most meaningful context. This can prevent silent failures and obscure error sources, particularly in complex scenarios like stream operations and functional interfaces.

Catching Null Early

By using Object.requireNonNull(param), you ensure that the null check happens immediately, at the point where the variable is first used. This provides a clearer and more immediate indication of the problem.

Consider this example: You have a functional interface with a default method. If you do not check the not-null parameter at that point, a null pointer could be thrown without indicating the correct line.

    interface MyFunctionalInterface<T> {
        boolean test(T t);

        default MyFunctionalInterface<T> or(MyFunctionalInterface<T> other) {
            return (T t) -> test(t) || other.test(t);
        }
    }

    public static void main(String[] args){
        MyFunctionalInterface<String> isEmpty = String::isEmpty;
        MyFunctionalInterface<String> allCharacters = s -> s.chars().allMatch(Character::isLetter);
        // This piece of code does not execute at this point   
        MyFunctionalInterface<String> isEmptyOrAllCharacters = isEmpty.or(null); 

        // here does not throw NullPointerException because the first condition is true
        System.out.println(isEmptyOrAllCharacters.test(""));

        // here it will throw NullPointerException but with wrong line number
        System.out.println(isEmptyOrAllCharacters.test("123"));

    }
   

If we check in the method the none null value, the NullPointerException is thrown as soon as the null is encountered, making it clear that the issue is with the list containing a null value.

   @FunctionalInterface
    interface MyFunctionalInterface<T> {
        boolean test(T t);

        default MyFunctionalInterface<T> or(MyFunctionalInterface<T> other) {
            Objects.requireNonNull(other);
            return (T t) -> test(t) || other.test(t);
        }
    }

    public static void main(String[] args){
        MyFunctionalInterface<String> isEmpty = String::isEmpty;
        MyFunctionalInterface<String> allCharacters = s -> s.chars().allMatch(Character::isLetter);

        MyFunctionalInterface<String> isEmptyOrAllCharacters = isEmpty.or(null); // <--- This piece of code does not execute at this point

        // here does not throw NullPointerException because the first condition is true
        System.out.println(isEmptyOrAllCharacters.test(""));

        // here it will throw NullPointerException but with wrong line number
        System.out.println(isEmptyOrAllCharacters.test("123"));

    }

In conclusion, by incorporating Object.requireNonNull(param) into your code, you adhere to the “fail fast” principle, catching null-related issues immediately and ensuring clearer, more maintainable code.

Nuria.

ReDoS in Java > 8: Regular Expression Denial of Service

Today, I was delving into Java security practices, specifically the concept of Whitelisting. Whitelisting involves explicitly specifying what is allowed rather than blocking what is not, as blacklisting can often miss emerging threats.

One effective approach to whitelisting is to validate input data as early as possible. Depending on the type of input, this can be straightforward or complex and frequently requires the use of regular expressions. However, at this point, I was cautioned about Regular Expression Denial of Service (ReDoS), prompting me to investigate this issue further.

Before diving into prevention methods—though it’s always good to follow best practices—I wanted to test firsthand how much damage a poorly constructed regular expression could cause on my machine.

The OWASP ReDoS page provides several examples. I wrote and executed a Java class with these examples, but I noticed no significant delay in the regular expression’s response.

Experimenting with Different Java Versions

My project was initially configured with Java 17. When I switched to Java 8, I could clearly observe the impact of a poorly designed regular expression and how it could lead to ReDoS. However, with Java 17, the same patterns did not cause any noticeable delay.

Improvements in Java 9 and Beyond

Upon further reading, I discovered that starting from Java 9, the efficiency of regular expression evaluation has been enhanced, reducing the likelihood of catastrophic backtracking. These improvements result from various optimizations and additional protections integrated into the regex engine.

Demonstration Videos

Here are some videos demonstrating the examples with Java 17 and Java 8. You can see the stark difference in how these versions handle potential ReDoS attacks:

Java 8:

Java 8
Java 17


By understanding these differences and improvements, we can better appreciate the advancements in Java's handling of regular expressions and apply safer practices in our code.

DuckDuckGo mail – mail without trackers

First tip: Use DuckDuckGo to maintain privacy while browsing.

Second tip: Use DuckDuckGo Mail. This privacy-focused email protection service provides users with a unique @duck.com email address. It forwards incoming emails to your regular inbox while removing trackers that can collect personal information. This service enhances your privacy by preventing advertisers from tracking your email activity and keeping your personal email address hidden.

Just go to duckduckgo.com/mail (maybe you should install an extension):

Configure new address:

And then use this address to receive clean emails:

Nuria.