Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
c5eb7e1
Refactor EVM migration tests into organized test files
Oct 3, 2025
3d2d4ac
Refactor + comparison feature: snapshot_info.py: function simplificat…
Oct 17, 2025
7f52e45
Enhance EVM migration tests with comprehensive failure reporting and …
Oct 17, 2025
657fee9
Refactor EVM migration tests for cleaner, simpler code
Oct 17, 2025
4a48acb
Fix EVM migration test failures
Oct 19, 2025
d301fce
Fix chain metadata test and add deterministic storage accounts
Oct 19, 2025
b8092f6
Fix non-deterministic accounts in precompile_direct test
Oct 19, 2025
fd54b53
Fix storage test structure for proper migration testing
Oct 19, 2025
21f6904
Make ALL storage test methods read-only for proper migration testing
Oct 19, 2025
17d3744
Extract storage write functionality into separate test methods
Oct 19, 2025
92c43ce
Refactor EVM migration tests for better reliability and debugging
Oct 20, 2025
bc9bb6f
Simplify chain_info tests to remove volatile fields for stable migrat…
Oct 20, 2025
ad47362
Refactor calldata_heavy tests to improve test architecture
Oct 20, 2025
d515716
Fix EVM event filtering timing issue
Oct 21, 2025
2d217e8
Add nested_gas_used to gas fields list for proper filtering
Oct 22, 2025
f6503c9
Add all MCOPY tests to gas-sensitive list for migration stability
Oct 24, 2025
bb5924e
Fix flake8 line length violations in EVM test files
Oct 24, 2025
a8d743d
Remove volatile fields and fix documentation references
Oct 24, 2025
db8a716
Fix comprehensive flake8 violations across test files
Oct 24, 2025
ddcbd92
Fix final flake8 violations for clean codebase
Oct 24, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 111 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

- [Introduction](#introduction)
- [Preparation](#preparation)
- [EVM Migration Tests](#evm-migration-tests)
- [Limitation](#limitation)
- [QA](#QA)

Expand Down Expand Up @@ -34,11 +35,120 @@ ETH_URL = 'http://127.0.0.1:9936'
pytest
```

# Runtime upgradae test
# Runtime upgrade test
```
RUNTIME_UPGRADE_PATH=~/PublicSMB/peaq_dev_runtime.compact.compressed.0.0.8.wasm python3 tools/runtime_upgrade.py
RUNTIME_UPGRADE_PATH=~/PublicSMB/peaq_dev_runtime.compact.compressed.0.0.8.wasm pytest
```

# EVM Migration Tests

The EVM migration test suite provides comprehensive validation of EVM functionality during runtime upgrades. Tests are organized into 5 specialized files covering 19 different smart contracts.

## Test Structure

### 📁 Test Files
- **`evm_migration_tokens_test.py`** - Token standards (ERC20, ERC721, ERC1155)
- **`evm_migration_calls_test.py`** - Call operations (DelegateCall, CallTest, Reentry, Calldata)
- **`evm_migration_storage_test.py`** - Storage operations (Storage, Upgrade, Struct)
- **`evm_migration_precompile_test.py`** - Precompile operations (ecrecover, sha256, etc.)
- **`evm_migration_advanced_test.py`** - Advanced features (Events, Gas, EIP-1153, EIP-5656)

### 🧪 Test Execution Modes
1. **Pre-Migration Tests**: Validate functionality before runtime upgrade
2. **Post-Migration Tests**: Verify consistency after runtime upgrade with automatic comparison

## Running EVM Migration Tests

### Run All Migration Tests
```bash
pytest tests/evm_migration_*_test.py -v -m eth
```

### Run Specific Categories
```bash
# Token standards testing
pytest tests/evm_migration_tokens_test.py -v

# Call operations testing
pytest tests/evm_migration_calls_test.py -v

# Storage operations testing
pytest tests/evm_migration_storage_test.py -v

# Precompile operations testing
pytest tests/evm_migration_precompile_test.py -v

# Advanced features testing
pytest tests/evm_migration_advanced_test.py -v
```

### Run Individual Tests
```bash
# Test specific contract before migration
pytest tests/evm_migration_tokens_test.py::TestEVMTokensMigration::test_erc20_before_migration -v

# Test with runtime upgrade
RUNTIME_UPGRADE_PATH=~/path/to/runtime.wasm pytest tests/evm_migration_tokens_test.py::TestEVMTokensMigration::test_erc20_after_migration -v
```

### View Test Output
```bash
# See detailed output including print statements
pytest tests/evm_migration_advanced_test.py -v -s
```

## Gas Tolerance Mechanism

The framework includes **smart gas tolerance handling** for tests sensitive to gas cost changes:

- **Gas-sensitive tests**: EIP-1153 (transient storage), EIP-5656 (MCOPY), gas consumption tests
- **Behavior**: Compares all functional fields while ignoring gas-related fields
- **Logging**: Reports gas changes as informational (not failures)

**Example Output:**
```
✅ Gas changes detected in transient_storage_tests (expected behavior):
total_gas_used: 136152 → 116252 (-14.6%)
```

**Why needed**: Gas costs legitimately change during runtime upgrades due to optimizations and EVM improvements.

## Test Coverage

| Category | Contracts | Coverage |
|----------|-----------|----------|
| **Token Standards** | ERC20, ERC721, ERC1155 | Standard token operations, minting, transfers |
| **Call Operations** | DelegateCall, CallTest, Reentry, Calldata | Proxy patterns, reentrancy protection, data handling |
| **Storage** | Storage, Upgrade, Struct | State persistence, upgradeable contracts, complex data |
| **Precompiles** | Standard Ethereum precompiles | ecrecover, sha256, ripemd160, identity, modexp |
| **Advanced** | Events, Gas, EIP-1153, EIP-5656 | Logging, optimization, transient storage, MCOPY |

## Migration Testing Flow

1. **Setup**: Deploy contracts and fund test accounts
2. **Pre-Migration**: Execute and store baseline behavior
3. **Runtime Upgrade**: Perform blockchain runtime upgrade
4. **Post-Migration**: Re-execute and compare with baseline
5. **Validation**: Ensure functional consistency (with gas tolerance)

## Trade-offs and Performance Considerations

**Sequential Execution Required:**
- EVM migration tests **cannot run in parallel** due to shared parachain instance
- Each test file performs `restart_with_setup()` = full parachain restart
- Running all 5 files = 5 separate parachain restarts

**Time Implications:**
- Total time = (5 × parachain_restart_time) + actual_test_time
- Each restart includes blockchain initialization, genesis setup, funding accounts
- Consider this when planning CI/CD pipeline timing

**Recommended Usage:**
- **Development**: Run individual files (`pytest tests/evm_migration_tokens_test.py`)
- **CI/CD**: Run full suite sequentially for comprehensive validation
- **Debugging**: Target specific domains to reduce restart overhead

# Limitation
1. In the peaq network, the standalone chain and parachain have different features and parameters; therefore, some tests may not pass, for example, the block creation time test and DID RPC test.
2. This project requires the dependent libraries whose version is higher than 0.9.29 because of the weight structure.
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ peaq-py==0.2.2
eth-account==0.9.0
web3==6.11.2
pytest==7.4.3
pytest-check==2.6.0
python-on-whales==0.66.0
eth-typing==3.5.2
eth-utils==2.3.1
Expand Down
147 changes: 147 additions & 0 deletions tests/evm_migration_advanced_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
"""
EVM Migration Test Suite - Advanced Features
This test file focuses on advanced EVM features including EIPs, events, error handling, and gas operations.
"""
import pytest
import unittest
from substrateinterface import SubstrateInterface
from tools.constants import KP_GLOBAL_SUDO, WS_URL, ETH_URL
from tools.runtime_upgrade import wait_until_block_height
from tools.peaq_eth_utils import get_eth_info
from peaq.sudo_extrinsic import funds
from web3 import Web3
from tests.utils_func import restart_with_setup, start_runtime_upgrade_only, is_runtime_upgrade_test
from tests.evm_sc.event import EventSCBehavior
from tests.evm_sc.error_handling import ErrorHandlingSCBehavior
from tests.evm_sc.gas import GasSCBehavior
from tests.evm_sc.eip1153_transient import EIP1153TransientTestBehavior
from tests.evm_sc.eip5656_mcopy import EIP5656MCOPYTestBehavior


@pytest.mark.eth
@pytest.mark.detail_upgrade_check
class TestEVMAdvancedMigration(unittest.TestCase):
"""Test advanced EVM features behavior during migration"""

def setUp(self):
"""Setup test environment and initialize contracts"""
restart_with_setup()
wait_until_block_height(SubstrateInterface(url=WS_URL), 3)
self._substrate = SubstrateInterface(url=WS_URL)
self._w3 = Web3(Web3.HTTPProvider(ETH_URL))

# Initialize advanced feature contracts
self._event = EventSCBehavior(self, self._w3, get_eth_info())
self._error_handling = ErrorHandlingSCBehavior(self, self._w3, get_eth_info())
self._gas = GasSCBehavior(self, self._w3, get_eth_info())
self._eip1153 = EIP1153TransientTestBehavior(self, self._w3, get_eth_info())
self._eip5656 = EIP5656MCOPYTestBehavior(self, self._w3, get_eth_info())

# Compose arguments for all contracts
self._event.compose_all_args()
self._error_handling.compose_all_args()
self._gas.compose_all_args()
self._eip1153.compose_all_args()
self._eip5656.compose_all_args()

# Fund all required accounts
ss58_addrs = []
ss58_addrs += self._event.get_fund_ss58_keys()
ss58_addrs += self._error_handling.get_fund_ss58_keys()
ss58_addrs += self._gas.get_fund_ss58_keys()
ss58_addrs += self._eip1153.get_fund_ss58_keys()
ss58_addrs += self._eip5656.get_fund_ss58_keys()

funds(self._substrate, KP_GLOBAL_SUDO, ss58_addrs, 1000 * 10**18)

# Deploy all contracts
self._event.deploy()
self._error_handling.deploy()
self._gas.deploy()
self._eip1153.deploy()
self._eip5656.deploy()

@pytest.mark.skipif(is_runtime_upgrade_test() is True, reason="No-upgrade test")
def test_event_no_upgrade(self):
"""Test event functionality without runtime upgrade"""
print("\n=== Testing Event No Upgrade ===")
self._event.run_test_scenario()
print("✅ Event no-upgrade test PASSED")

@pytest.mark.skipif(is_runtime_upgrade_test() is True, reason="No-upgrade test")
def test_error_handling_no_upgrade(self):
"""Test error handling functionality without runtime upgrade"""
print("\n=== Testing ErrorHandling No Upgrade ===")
self._error_handling.run_test_scenario()
print("✅ ErrorHandling no-upgrade test PASSED")

@pytest.mark.skipif(is_runtime_upgrade_test() is True, reason="No-upgrade test")
def test_gas_no_upgrade(self):
"""Test gas functionality without runtime upgrade"""
print("\n=== Testing Gas No Upgrade ===")
self._gas.run_test_scenario()
print("✅ Gas no-upgrade test PASSED")

@pytest.mark.skipif(is_runtime_upgrade_test() is True, reason="No-upgrade test")
def test_eip1153_no_upgrade(self):
"""Test EIP-1153 transient storage without runtime upgrade"""
print("\n=== Testing EIP1153 No Upgrade ===")
self._eip1153.run_test_scenario()
print("✅ EIP1153 no-upgrade test PASSED")

@pytest.mark.skipif(is_runtime_upgrade_test() is True, reason="No-upgrade test")
def test_eip5656_no_upgrade(self):
"""Test EIP-5656 MCOPY opcode without runtime upgrade"""
print("\n=== Testing EIP5656 No Upgrade ===")
self._eip5656.run_test_scenario()
print("✅ EIP5656 no-upgrade test PASSED")

@pytest.mark.skipif(is_runtime_upgrade_test() is False, reason="Upgrade test")
def test_event_with_upgrade(self):
"""Test event functionality with runtime upgrade and verify consistency"""
print("\n=== Testing Event With Upgrade ===")
self._event.run_test_scenario()
start_runtime_upgrade_only()
self._event.run_post_upgrade_scenario()
self._event.check_migration_difference()
print("✅ Event with-upgrade test PASSED")

@pytest.mark.skipif(is_runtime_upgrade_test() is False, reason="Upgrade test")
def test_error_handling_with_upgrade(self):
"""Test error handling functionality with runtime upgrade and verify consistency"""
print("\n=== Testing ErrorHandling With Upgrade ===")
self._error_handling.run_test_scenario()
start_runtime_upgrade_only()
self._error_handling.run_post_upgrade_scenario()
self._error_handling.check_migration_difference()
print("✅ ErrorHandling with-upgrade test PASSED")

@pytest.mark.skipif(is_runtime_upgrade_test() is False, reason="Upgrade test")
def test_gas_with_upgrade(self):
"""Test gas functionality with runtime upgrade and verify consistency"""
print("\n=== Testing Gas With Upgrade ===")
self._gas.run_test_scenario()
start_runtime_upgrade_only()
self._gas.run_post_upgrade_scenario()
self._gas.check_migration_difference()
print("✅ Gas with-upgrade test PASSED")

@pytest.mark.skipif(is_runtime_upgrade_test() is False, reason="Upgrade test")
def test_eip1153_with_upgrade(self):
"""Test EIP-1153 transient storage with runtime upgrade and verify consistency"""
print("\n=== Testing EIP1153 With Upgrade ===")
self._eip1153.run_test_scenario()
start_runtime_upgrade_only()
self._eip1153.run_post_upgrade_scenario()
self._eip1153.check_migration_difference()
print("✅ EIP1153 with-upgrade test PASSED")

@pytest.mark.skipif(is_runtime_upgrade_test() is False, reason="Upgrade test")
def test_eip5656_with_upgrade(self):
"""Test EIP-5656 MCOPY opcode with runtime upgrade and verify consistency"""
print("\n=== Testing EIP5656 With Upgrade ===")
self._eip5656.run_test_scenario()
start_runtime_upgrade_only()
self._eip5656.run_post_upgrade_scenario()
self._eip5656.check_migration_difference()
print("✅ EIP5656 with-upgrade test PASSED")
Loading