Security·8 min का पठन·Solingo द्वारा

Echidna — Smart Contracts के लिए Property-Based Fuzzing

Automated testing tool जो हजारों random inputs से आपके contract में bugs खोजता है।

# Echidna — Smart Contracts के लिए Property-Based Fuzzing

Manual testing से bugs miss हो जाते हैं। Echidna random inputs generate करके edge cases automatically test करता है।

Fuzzing क्या है?

Fuzzing = random/malformed inputs से program break करने की कोशिश।

Traditional testing:

function testTransfer() public {

token.transfer(alice, 100);

assertEq(token.balanceOf(alice), 100);

}

Fuzzing:

function testTransfer(address to, uint amount) public {

// Echidna automatically tries:

// - amount = 0

// - amount = type(uint).max

// - to = address(0)

// - to = address(this)

// ... और हजारों combinations

}

Echidna Installation

# Homebrew (macOS)

brew install echidna

# Docker

docker pull trailofbits/echidna

# Binary (Linux/Windows)

# GitHub releases से download करें

Basic Example: Token Contract

contract Token {

mapping(address => uint) public balances;

uint public totalSupply;

function mint(address to, uint amount) public {

balances[to] += amount;

totalSupply += amount;

}

function burn(address from, uint amount) public {

balances[from] -= amount;

totalSupply -= amount;

}

}

Echidna Test Contract

contract TokenTest is Token {

// Property: total supply = sum of balances

function echidna_total_supply_correct() public view returns (bool) {

return totalSupply >= balances[msg.sender];

}

// Property: balances never negative (implicit — Solidity reverts)

// Property: no overflow

function echidna_no_overflow() public view returns (bool) {

return totalSupply <= type(uint128).max;

}

}

Run करें

echidna-test token.sol --contract TokenTest

Output:

echidna_total_supply_correct: failed!

Call sequence:

mint(0x0, 1000)

burn(0x0, 500)

mint(0x10000, 2000)

Echidna ने bug find किया! Total supply का calculation multiple addresses के साथ break हो रहा है।

Property Types

1. Invariants

Always true होनी चाहिए:

function echidna_vault_solvent() public view returns (bool) {

return vault.totalAssets() >= vault.totalDebt();

}

2. State Transitions

Valid states:

enum State { Pending, Active, Closed }

State public state;

function echidna_valid_state() public view returns (bool) {

return uint(state) <= 2;

}

3. Conservation Laws

function echidna_conservation() public view returns (bool) {

return address(this).balance + withdrawnAmount == initialBalance;

}

Real-World Example: AMM Pool

contract AMMPool {

uint public reserveA;

uint public reserveB;

uint public constant k;

constructor() {

k = 1000000 * 1e18;

reserveA = 1000 * 1e18;

reserveB = 1000 * 1e18;

}

function swap(uint amountIn, bool aForB) public {

if (aForB) {

uint amountOut = reserveB - (k / (reserveA + amountIn));

reserveA += amountIn;

reserveB -= amountOut;

} else {

uint amountOut = reserveA - (k / (reserveB + amountIn));

reserveB += amountIn;

reserveA -= amountOut;

}

}

}

Properties

contract AMMTest is AMMPool {

// Property 1: Constant product

function echidna_constant_product() public view returns (bool) {

return reserveA * reserveB >= k;

}

// Property 2: Reserves never zero

function echidna_reserves_positive() public view returns (bool) {

return reserveA > 0 && reserveB > 0;

}

// Property 3: No free money

uint initialValue;

function echidna_no_profit() public view returns (bool) {

return reserveA + reserveB <= initialValue * 2;

}

}

Configuration: echidna.yaml

testMode: assertion

testLimit: 50000

seqLen: 100

contractAddr: "0x00a329c0648769A73afAc7F9381E08FB43dBEA72"

deployer: "0x10000"

sender: ["0x10000", "0x20000", "0x30000"]

Advanced: Corpus & Coverage

Echidna interesting inputs save करता है:

echidna-test contract.sol --corpus-dir=corpus

Subsequent runs में:

  • Corpus से seeds use होते हैं
  • Faster bug discovery
  • Regression testing

Coverage Report

echidna-test contract.sol --coverage

यह HTML report generate करता है जो uncovered branches दिखाता है।

Echidna vs Foundry Fuzz

| Feature | Echidna | Foundry |

|---|---|---|

| Input Generation | Smarter (grammar-based) | Random |

| State Management | Persistent | Per-test reset |

| Speed | Slower | Faster |

| Learning Curve | Steeper | Easier |

Recommendation: Dono use करें।

  • Foundry fuzz — quick unit tests
  • Echidna — deep property testing

Common Pitfalls

1. Weak Properties

// ❌ Too weak — हमेशा true

function echidna_weak() public view returns (bool) {

return true;

}

// ✅ Meaningful

function echidna_strong() public view returns (bool) {

return invariantCheck();

}

2. Not Enough Sequences

Default testLimit कम हो सकता है:

testLimit: 100000  # increase

3. Missing Preconditions

function swap(uint amountIn, bool aForB) public {

require(amountIn > 0); // precondition add करें

// ...

}

निष्कर्ष

Echidna smart contract testing में revolution है:

  • Automated edge case discovery
  • Property-based approach
  • Real bugs in production code

हर serious Solidity project को Echidna use करना चाहिए। यह manual testing की limitations को eliminate करता है।

अगला step: अपने contracts में invariants define करें और Echidna run करें। आप surprised होंगे कितने bugs मिलते हैं।

Practice में लगाने के लिए तैयार हैं?

Solingo पर interactive exercises के साथ इन concepts को apply करें।

मुफ्त में शुरू करें