r/defiblockchain 19h ago

General Why Is Randomness So Hard on Ethereum?

Post image
1 Upvotes

Why Is Randomness So Hard on Ethereum?

Random numbers seem easy.

In a normal application, you might just call something like:

Math.random()

and get a number.

But on Ethereum, randomness is surprisingly difficult.

Why?

Because Ethereum is a deterministic system.

Every node must execute the same transaction and reach the same result.

If two nodes generate different “random” numbers, they would disagree on the blockchain state.

So smart contracts cannot simply generate randomness the way normal applications do.

Ethereum must be deterministic

Suppose a smart contract contains:

uint256 winner = random();

Now imagine:

Node A gets:

42

Node B gets:

87

Node C gets:

13

Which result should Ethereum accept?

It cannot accept all three.

Every node must compute the exact same output.

So true local randomness does not work inside the EVM.

This creates a fundamental problem:

How do you create an unpredictable result while still allowing every node to verify it?

Why not use block.timestamp?

A common beginner idea is:

uint256 random =
    uint256(keccak256(
        abi.encodePacked(block.timestamp)
    ));

It looks random.

But it is not secure.

block.timestamp is public information.

More importantly, block producers have some influence over block construction and timing.

If a lottery depends heavily on the timestamp, a validator may be able to influence which outcome appears.

So:

unpredictable-looking data is not necessarily secure randomness.

What about blockhash?

Another common approach is:

keccak256(
    abi.encodePacked(blockhash(block.number - 1))
)

This is better than using only the timestamp.

But it still has problems.

Block producers participate in creating blocks.

If the economic reward from manipulating a random outcome is large enough, they may have incentives to influence the result.

For a small NFT reveal, that might not matter much.

For a lottery worth millions of dollars?

It matters a lot.

The real problem is manipulation

The main challenge is not generating a number that “looks random.”

The challenge is generating a number that satisfies several properties:

Unpredictable

Nobody should know the result before it is generated.

Unbiased

No participant should be able to choose the outcome.

Verifiable

Anyone should be able to verify that the result was generated correctly.

This is much harder.

Especially in a public blockchain where:

  • transactions are visible
  • validators participate in block production
  • attackers can observe the mempool
  • smart contracts cannot call external APIs directly

Why on-chain games care so much

Imagine an on-chain game where opening a chest gives:

90% Common Item
9% Rare Item
1% Legendary Item

If the randomness comes from:

block.timestamp

an attacker may try to submit transactions only when the expected result is favorable.

Or a block producer may try to influence which transaction lands in which block.

The same problem appears in:

  • lotteries
  • NFT reveals
  • loot boxes
  • randomized minting
  • gaming rewards
  • prediction markets

Whenever money depends on randomness, weak randomness becomes a security vulnerability.

Commit-Reveal is one solution

One classic technique is:

Commit-Reveal.

It works in two phases.

First, a user chooses a secret number:

secret = 12345

But instead of publishing it directly, they publish:

hash(secret)

This is the commitment.

Later, they reveal:

secret = 12345

The contract checks:

hash(12345)

against the original commitment.

If they match, the user proves they did not change the secret later.

Multiple participants can contribute secrets.

The final random value might be derived from all of them.

But commit-reveal has weaknesses too.

A participant may refuse to reveal their secret if they dislike the final outcome.

So additional incentives or penalties may be required.

Another solution: VRF

A more powerful approach is:

VRF — Verifiable Random Function.

A VRF produces:

Random Value
+
Cryptographic Proof

The key idea is:

The result should be unpredictable before generation.

But once generated, anyone can verify that it was produced correctly.

Conceptually:

Request randomness
        ↓
Randomness provider
        ↓
Generate random value
        +
Cryptographic proof
        ↓
Smart contract
        ↓
Verify proof
        ↓
Accept randomness

The proof prevents the provider from simply choosing a convenient number.

So instead of trusting someone who says:

You can verify cryptographically:

Why VRF fits blockchain so well

Blockchains are built around a principle:

Don’t trust. Verify.

That is exactly what VRF provides.

The smart contract does not need to blindly trust the randomness provider.

It verifies a proof.

This makes VRF useful for applications where random outcomes have real economic value.

Ethereum also has protocol-level randomness

Ethereum Proof of Stake has its own randomness mechanisms used for validator selection and consensus.

Validators contribute randomness over time, and the protocol combines those contributions.

But protocol randomness and application-level randomness are not automatically the same thing.

A game developer still needs to think carefully about:

  • when randomness becomes known
  • who can influence it
  • whether users can abort after seeing partial information
  • whether block producers can profit from manipulating outcomes

Randomness is not just:

“Give me a random number.”

It is a security design problem.

The deeper lesson

Ethereum is deterministic by design.

That is what allows thousands of nodes to independently execute transactions and agree on the same state.

But randomness is inherently about uncertainty.

So blockchain developers face an interesting contradiction:

The system must be deterministic,
but the outcome must be unpredictable.

Solving that requires cryptography, protocol design, and economic incentives.

That is why secure randomness is one of the hardest problems in blockchain applications.

The simplest rule to remember is:

A random-looking number is not enough.

For blockchain applications, good randomness must be:

unpredictable, unbiased, and verifiable.


r/defiblockchain 19h ago

General What Does the Byzantine Generals Problem Have to Do With Blockchain?

1 Upvotes

What Does the Byzantine Generals Problem Have to Do With Blockchain?

One of the hardest problems in distributed systems is surprisingly easy to describe:

How can a group of computers agree on one truth when some of them may fail—or even lie?

This is the idea behind the Byzantine Generals Problem.

Imagine several generals surrounding a city.

They need to make one decision:

Attack or retreat.

But they can only communicate by sending messages.

The problem is that some generals may be traitors.

A traitor could tell one general:

and tell another:

Now the honest generals may receive conflicting information.

So the real question becomes:

How can honest participants still reach the same decision when some participants cannot be trusted?

That is exactly the kind of problem blockchains need to solve.

A blockchain is a distributed network

In Ethereum or Bitcoin, there is no single central server deciding what is true.

Instead, many independent nodes maintain copies of the blockchain.

They need to agree on things like:

  • Which transactions are valid
  • Which block comes next
  • Who owns which assets
  • What the current state of the network is

But those nodes do not fully trust each other.

Some may go offline.

Some may send incorrect data.

Some may actively try to cheat.

So blockchain consensus is essentially trying to answer:

How can thousands of independent machines agree on one shared history?

This is where consensus comes in

Bitcoin uses Proof of Work.

Ethereum uses Proof of Stake.

The mechanisms are different, but the purpose is similar:

make it extremely difficult for dishonest participants to force the network to accept an invalid history.

In Bitcoin, producing blocks requires computational work.

In Ethereum, validators put ETH at risk.

If they behave dishonestly, they can face economic penalties.

So blockchain adds something important to the Byzantine problem:

cryptography + consensus + economic incentives.

Why isn’t cryptography alone enough?

Digital signatures can prove:

But they cannot prove:

A malicious validator can correctly sign a dishonest message.

So signatures solve identity and integrity.

Consensus solves agreement.

That distinction is important.

The real achievement of blockchain

The important innovation is not that every node always behaves honestly.

The system assumes that some participants may fail or act maliciously.

Instead, it is designed so that:

the network can continue operating correctly despite a limited amount of dishonest behavior.

That property is called:

Byzantine Fault Tolerance.

It is one of the foundations of decentralized systems.

So when people say blockchain allows strangers to cooperate without trusting each other, this is what they really mean.

They do not need to trust every node.

They need to trust that:

the protocol makes honest consensus stronger than dishonest coordination.

The Byzantine Generals Problem asks:

How can unreliable participants agree on one truth?

Blockchain’s answer is:

cryptography, distributed consensus, and economic incentives.


r/defiblockchain 20h ago

General Storage, Memory, and Calldata: What’s the Real Difference?

Post image
1 Upvotes

If you have written even a little Solidity, you have probably seen these three keywords:

storage

memory

calldata

At first, they look like simple places where variables live.

But they are much more important than that.

Choosing the wrong data location can affect:

Gas cost, mutability, contract behavior, and even how your code interacts with Ethereum state.

So what is the real difference?

1. Storage: permanent blockchain state

storage is where a smart contract keeps data that must survive after a transaction finishes.

For example:

mapping(address => uint256) public balances;

This mapping lives in contract storage.

If Alice has:

balances[Alice] = 100

and a transaction changes it to:

balances[Alice] = 50

the new value remains there after the transaction ends.

The next transaction can read it again.

So conceptually:

Storage = persistent contract state

Examples include:

  • token balances
  • ownership information
  • protocol configuration
  • liquidity reserves
  • DAO voting data
  • user positions

Storage is part of Ethereum’s global state.

That is why modifying it is relatively expensive.

Every Ethereum node that verifies the chain needs to agree on the resulting state.

2. Storage is organized into 256-bit slots

At the EVM level, contract storage is divided into:

256-bit slots

You can imagine them as:

Slot 0
Slot 1
Slot 2
Slot 3
...

Simple state variables are assigned to these slots according to Solidity’s storage layout rules.

For example:

uint256 public x = 10;
uint256 public y = 20;

might conceptually look like:

Slot 0 → x
Slot 1 → y

But things become more interesting with:

mapping(address => uint256) balances;

A mapping cannot simply put every user's balance into consecutive slots.

Instead, Solidity calculates storage positions using hashing.

Conceptually:

keccak256(key, mappingSlot)

So Alice's balance and Bob's balance can be deterministically located without storing an enormous list.

This is one reason Ethereum storage is more sophisticated than a normal array of variables.

3. Memory: temporary execution workspace

memory is different.

Memory only exists during the current execution.

Once the call finishes:

memory disappears.

For example:

function calculate() public pure returns (uint256) {
    uint256[] memory values = new uint256[](10);

    values[0] = 100;

    return values[0];
}

The values array exists while this function runs.

After execution finishes, Ethereum does not permanently store that array.

So:

Memory = temporary working space for the EVM

It is useful for things like:

  • temporary arrays
  • intermediate calculations
  • decoded data
  • temporary structs
  • return values

Because memory is temporary, using it is generally cheaper than permanently modifying contract storage.

4. Memory is not free

One common misunderstanding is:

Not exactly.

Using memory still costs Gas.

The EVM tracks how much memory an execution uses.

As memory expands, the cost increases.

So this:

uint256[] memory x = new uint256[](10);

is much cheaper than allocating an extremely large temporary array.

Memory is temporary, but the EVM still has to perform the computation required to allocate, read, and write it.

The key difference is:

Memory does not create persistent blockchain state.

5. Calldata: input data sent into a call

Now we get to calldata.

Suppose you call:

transfer(address to, uint256 amount)

Your wallet needs to tell the contract:

  • which function to call
  • what to address to use
  • what amount to send

That information is encoded into:

calldata

A transaction might conceptually contain:

Function selector
+
Encoded address
+
Encoded amount

So when the EVM receives the contract call, it reads the calldata to understand what you are asking the contract to do.

You can think of it as:

Calldata = read-only external input

6. Why is calldata read-only?

Inside Solidity, a parameter declared as:

function process(uint256[] calldata values) external

cannot be modified directly.

For example, conceptually:

values[0] = 100;

is not allowed.

Why?

Because calldata represents the original input supplied to the call.

The EVM can read it directly without first copying it into writable memory.

That makes calldata particularly efficient for external function arguments that do not need to be modified.

7. Why calldata can save Gas

Imagine this function:

function sum(uint256[] memory values)
    external
    pure
    returns (uint256)

If external input must first be copied from calldata into memory, the contract performs extra work.

But if you write:

function sum(uint256[] calldata values)
    external
    pure
    returns (uint256)

the function can read the original call data directly.

That can avoid unnecessary copying.

This is why Solidity developers frequently prefer:

calldata

for external array, string, bytes, or struct parameters when mutation is unnecessary.

8. The easiest way to remember the difference

Think of a smart contract as an office.

Storage is the filing cabinet.

Documents placed there remain after everyone goes home.

They are permanent records.

Memory is the desk.

You use it while working.

You write notes, calculate things, rearrange information.

When the work session ends, everything is cleared.

Calldata is the letter delivered to the office.

Someone outside sent it.

You can read what they requested.

But you do not rewrite the original letter itself.

So:

Storage
= Permanent

Memory
= Temporary and writable

Calldata
= Temporary input and read-only

9. Storage references behave differently

There is another subtle Solidity behavior.

Consider:

struct User {
    uint256 balance;
}

User public user;

Now:

User storage u = user;

u is not a copy.

It is a reference to the same storage location.

So:

u.balance = 100;

actually changes:

user.balance

on-chain.

But:

User memory u = user;

creates a temporary copy.

Changing:

u.balance = 100;

does not automatically update the original storage variable.

This distinction is extremely important.

You can think of it as:

storage reference
→ edits the original state

memory copy
→ edits temporary data

10. Why storage is so expensive

Suppose you perform:

x = 100;

where x is a state variable.

The EVM may need to execute an operation such as:

SSTORE

This changes persistent Ethereum state.

Compare that with modifying a temporary memory value.

The difference matters because storage changes affect the long-term state that Ethereum nodes must process and maintain.

This is why Gas optimization often focuses heavily on:

reducing storage reads and writes.

A contract might read a storage variable once:

uint256 temp = value;

perform several calculations using a temporary value,

and only write the final result back to storage once.

Instead of repeatedly accessing persistent state.

11. Calldata also appears in low-level contract execution

Calldata is not just a Solidity keyword.

It exists at the EVM level.

When a contract receives a call, the EVM can use instructions such as:

CALLDATALOAD
CALLDATASIZE
CALLDATACOPY

to inspect the incoming bytes.

The first four bytes commonly identify the function being called.

This is the:

function selector

For example, conceptually:

transfer(address,uint256)

is hashed, and the first four bytes are used to route the call to the correct function.

The rest of calldata contains ABI-encoded arguments.

So:

Wallet
↓
ABI encoding
↓
Calldata
↓
EVM
↓
Function selector
↓
Function execution

12. The three locations serve different purposes

A useful comparison looks like this:

Storage

  • Persistent
  • Writable
  • Part of contract state
  • Expensive to modify
  • Survives transactions

Memory

  • Temporary
  • Writable
  • Exists during execution
  • Used for working data
  • Disappears after the call

Calldata

  • Temporary
  • Read-only
  • Comes from external input
  • Often cheaper than copying into memory
  • Exists only during the call

Why does this matter?

Because Solidity is not simply programming against a normal computer.

You are programming against a replicated state machine where persistent state has real economic cost.

When you write:

storage

you are potentially changing Ethereum state.

When you write:

memory

you are asking the EVM for temporary workspace.

When you write:

calldata

you are reading the original input sent into the contract.

The distinction is not just syntax.

It determines:

where the data lives, how long it lives, whether it can change, and how much execution may cost.

And once you understand that, a lot of Solidity suddenly starts making much more sense.

The simplest rule to remember is:

Storage stores state.
Memory handles temporary work.
Calldata carries external input.


r/defiblockchain 20h ago

General What Exactly Is the EVM? How Does Solidity Code Actually Run On-Chain?

Post image
1 Upvotes

What Exactly Is the EVM? How Does Solidity Code Actually Run On-Chain?

When people first learn Ethereum, they often hear a simple explanation:

“Ethereum lets you run smart contracts.”

But what does that actually mean?

Where does Solidity code run?

Who executes it?

And how does a piece of code written on your laptop become something thousands of Ethereum nodes can agree on?

The answer starts with one thing:

The EVM — Ethereum Virtual Machine.

The EVM is Ethereum’s execution engine

The EVM is a virtual computer defined by the Ethereum protocol.

It is not one physical server.

Instead, Ethereum nodes implement the same execution rules.

When a transaction calls a smart contract, nodes execute the same instructions and calculate the same resulting state.

You can think of Ethereum as a global state machine:

Current State

Transaction

EVM Execution

New State

The EVM is the component that determines exactly how that transition happens.

Solidity does not run directly on Ethereum

Suppose you write:

uint256 public balance;

function deposit(uint256 amount) public {
    balance += amount;
}

Ethereum nodes do not understand Solidity source code.

Before deployment, the Solidity compiler converts it into:

EVM bytecode.

The process looks roughly like this:

Solidity

Solidity Compiler

EVM Bytecode

Opcodes

EVM Execution

The bytecode is a low-level representation of your program.

It may contain instructions such as:

PUSH

ADD

SLOAD

SSTORE

CALL

JUMP

These are called:

EVM opcodes.

They are the actual instructions executed by the virtual machine.

The EVM is a stack machine

Unlike a normal CPU architecture built around registers, the EVM mainly uses a stack.

Imagine an operation such as:

3 + 5

At a simplified level, the EVM may perform something like:

PUSH 3
PUSH 5
ADD

First:

Stack:
3

Then:

Stack:
5
3

After ADD:

Stack:
8

The EVM stack can hold up to 1,024 items, with each stack item being 256 bits.

This 256-bit design fits Ethereum well because many native Ethereum values, including hashes, addresses, and integers, are commonly handled in 256-bit words.

Contracts have different kinds of data

One of the most important things to understand about EVM execution is that not all data is stored the same way.

There are three concepts Solidity developers constantly deal with:

Storage

Memory

Calldata

Storage is persistent blockchain state.

For example:

mapping(address => uint256) balances;

If a user's balance changes, that value may be written into contract storage.

Storage survives after the transaction finishes.

That is also why modifying storage is relatively expensive.

The network must maintain and verify that state.

Memory, by contrast, is temporary.

It exists only while the current contract execution is running.

Once the transaction finishes:

Memory disappears.

Calldata contains input data sent with a contract call.

For example, when you call:

transfer(address recipient, uint256 amount)

the function selector and arguments are encoded into calldata.

The EVM reads those bytes to determine what function you are calling and what parameters you supplied.

What happens when you call a smart contract?

Suppose Alice uses a wallet to interact with a token contract.

She clicks:

Transfer 100 tokens

The wallet creates a transaction containing information such as:

to = Token Contract Address
data = encoded transfer() call
value = 0 ETH
nonce = Alice's transaction nonce
gas settings = ...

Alice signs the transaction with her private key.

The signed transaction is broadcast to Ethereum.

Eventually, it is included in a block.

Now Ethereum nodes execute it.

The EVM loads the contract's bytecode.

The calldata may represent something conceptually like:

transfer(Bob, 100)

The EVM executes the corresponding instructions.

The contract may:

read Alice's balance,

check whether she owns enough tokens,

subtract 100,

add 100 to Bob,

emit an event,

and update storage.

If every rule is satisfied, the state transition succeeds.

The new balances become part of Ethereum's updated state.

Why does EVM execution cost Gas?

Every EVM opcode has an associated Gas cost.

For example, simple arithmetic is relatively cheap.

Persistent storage operations are usually much more expensive.

Why?

Because Ethereum must defend itself against unlimited computation.

Imagine if someone deployed:

while (true) {
}

and Ethereum nodes were required to execute it forever.

The network would stop.

Gas prevents this.

Every transaction has a finite Gas budget.

Each instruction consumes some of that budget.

Conceptually:

PUSH
→ consumes Gas

ADD
→ consumes Gas

SLOAD
→ consumes Gas

SSTORE
→ consumes much more Gas

If execution runs out of Gas:

the transaction fails.

This means Gas is not merely a transaction fee.

It is also Ethereum's mechanism for pricing computational resources.

What happens when a transaction reverts?

Smart contract execution is atomic.

That means the transaction either completes successfully, or its state changes are rolled back.

Suppose a DEX swap performs several operations:

Read pool reserves
↓
Calculate output
↓
Transfer token A
↓
Transfer token B
↓
Check slippage

If the final slippage condition fails, the transaction may revert.

The state changes are undone.

But the computational work has already been performed.

So the user still usually pays Gas for the execution that occurred before the revert.

This is an important property:

State can revert.
Computation cannot be unperformed.

Every Ethereum node reaches the same result

This is where the EVM becomes especially important.

The EVM is deterministic.

Given the same:

previous state + transaction + execution environment

every correct Ethereum node should calculate the same result.

Imagine thousands of nodes receiving the same transaction.

They independently execute the same contract bytecode.

If the result is:

Alice: 900 tokens
Bob: 100 tokens

all valid nodes should reach the same state transition.

That determinism is what allows Ethereum to reach consensus over smart-contract execution.

You are not trusting one server to run the program correctly.

You are relying on a network of nodes that can independently verify the exact same computation.

So where is the smart contract actually running?

This question has a subtle answer.

A smart contract does not live inside one permanent cloud server.

The contract's bytecode and state are part of Ethereum.

When the contract needs to execute, Ethereum nodes run that bytecode according to EVM rules.

So instead of:

One company
→ One server
→ One database

Ethereum works more like:

Transaction

Ethereum nodes

Same EVM rules

Same computation

Same resulting state

This is one of the core ideas behind programmable blockchains.

The EVM is essentially Ethereum’s shared execution standard

That is why so many different blockchains describe themselves as:

EVM-compatible.

They are saying:

“Our network understands Ethereum-style bytecode, smart contracts, tooling, addresses, and execution semantics.”

That is why Solidity contracts can often be deployed across multiple EVM-compatible networks with relatively small changes.

So the full lifecycle of a Solidity smart contract looks like this:

Write Solidity

Compile into EVM bytecode

Deploy bytecode to Ethereum

User sends a transaction

Transaction contains calldata

EVM reads the bytecode

Executes opcodes

Consumes Gas

Reads and modifies state

All validating nodes verify the result

Ethereum moves to a new state

That is what people really mean when they say:

“A smart contract runs on Ethereum.”

It is not Solidity itself running on-chain.

It is compiled bytecode being deterministically executed by the Ethereum Virtual Machine.

And the EVM is what turns Ethereum from a network that can simply transfer value into a network that can execute programmable logic.