Loading...
Loading...

Свойство | Тип | Описание | Практическое применение | Ограничения |
|---|---|---|---|---|
blockhash(blockNumber) | bytes32 | Хеш конкретного блока | Псевдослучайность, верификация | Только последние 256 блоков |
block.difficulty | uint256 | Сложность майнинга блока | Адаптивные алгоритмы | Только в PoW сетях |
block.gaslimit | uint256 | Лимит газа для блока | Оптимизация транзакций | Может изменяться |
block.coinbase | address | Адрес майнера блока | Награды майнерам | Может быть пулом |
contract NetworkAnalyzer { struct NetworkSnapshot { uint256 blockNumber; uint256 timestamp; uint256 difficulty; uint256 gasLimit; uint256 gasUsed; }
NetworkSnapshot[] public snapshots;
event NetworkSnapshotTaken(uint256 indexed snapshotId, uint256 blockNumber, uint256 difficulty);
function takeSnapshot() public { snapshots.push(NetworkSnapshot({ blockNumber: block.number, timestamp: block.timestamp, difficulty: block.difficulty, gasLimit: block.gaslimit, gasUsed: 0 // Будет заполнено позже }));
emit NetworkSnapshotTaken(snapshots.length - 1, block.number, block.difficulty); }
function analyzeNetworkLoad() public view returns ( string memory loadStatus, uint256 averageDifficulty, uint256 averageGasLimit ) { require(snapshots.length > 0, "Нет снимков для анализа");
uint256 totalDifficulty = 0; uint256 totalGasLimit = 0;
for (uint256 i = 0; i < snapshots.length; i++) { totalDifficulty += snapshots[i].difficulty; totalGasLimit += snapshots[i].gasLimit; }
averageDifficulty = totalDifficulty / snapshots.length; averageGasLimit = totalGasLimit / snapshots.length;
// Простая оценка загрузки сети if (averageGasLimit > 30000000) { loadStatus = "High"; } else if (averageGasLimit > 15000000) { loadStatus = "Medium"; } else { loadStatus = "Low"; } }}Свойство | Тип | Описание | Практическое применение | Важные замечания |
|---|---|---|---|---|
msg.sender | address | Непосредственный вызывающий | Контроль доступа, авторизация | Может быть EOA или контрактом |
msg.value | uint256 | Количество wei в транзакции | Депозиты, платежи | Только в payable функциях |
msg.data | bytes | Полные данные вызова | Логирование, проксирование | Содержит селектор + параметры |
msg.sig | bytes4 | Селектор функции | Идентификация функций | Первые 4 байта msg.data |
tx.origin | address | Изначальный отправитель | Отслеживание инициатора | ⚠️ ОПАСНО для авторизации! |
tx.gasprice | uint256 | Цена газа | Оптимизация газа | Сильно варьируется |
contract AccessControl { address public owner; mapping(address => bool) public allowedUsers; mapping(address => uint256) public userActivity;
event UserAdded(address indexed user, address indexed addedBy, uint256 timestamp); event ActivityLogged(address indexed user, string action, uint256 timestamp);
constructor() { owner = msg.sender; // Тот, кто развернул контракт }
modifier onlyOwner() { require(msg.sender == owner, "Только владелец может это сделать"); _; }
modifier onlyAllowed() { require(allowedUsers[msg.sender] || msg.sender == owner, "Доступ запрещён"); _; }
function addUser(address user) public onlyOwner { allowedUsers[user] = true; userActivity[msg.sender]++; // Увеличиваем активность владельца
emit UserAdded(user, msg.sender, block.timestamp); emit ActivityLogged(msg.sender, "Added user", block.timestamp); }
function restrictedFunction(string memory action) public onlyAllowed { userActivity[msg.sender]++;
emit ActivityLogged(msg.sender, action, block.timestamp); }
function getUserInfo(address user) public view returns ( bool isOwner, bool isAllowed, uint256 activity ) { isOwner = (user == owner); isAllowed = allowedUsers[user]; activity = userActivity[user]; }
// Функция для смены владельца function transferOwnership(address newOwner) public onlyOwner { require(newOwner != address(0), "Новый владелец не может быть нулевым адресом");
address oldOwner = owner; owner = newOwner;
emit ActivityLogged(oldOwner, "Transferred ownership", block.timestamp); }}tx.origin для авторизации!// ❌ УЯЗВИМЫЙ контрактcontract DangerousContract { address public owner;
constructor() { owner = tx.origin; // ОПАСНО! }
function withdraw() public { require(tx.origin == owner, "Не владелец"); // УЯЗВИМОСТЬ! payable(owner).transfer(address(this).balance); }
receive() external payable {}}
// ⚔️ Атакующий контрактcontract Attacker { DangerousContract target;
constructor(DangerousContract _target) { target = _target; }
function attack() public { // Если владелец DangerousContract вызовет эту функцию, // tx.origin будет равен владельцу, и деньги уйдут атакующему! target.withdraw(); }}
// ✅ БЕЗОПАСНЫЙ контрактcontract SafeContract { address public owner;
constructor() { owner = msg.sender; // БЕЗОПАСНО }
function withdraw() public { require(msg.sender == owner, "Не владелец"); // БЕЗОПАСНО payable(owner).transfer(address(this).balance); }
receive() external payable {}}contract PaymentProcessor { mapping(address => uint256) public deposits; mapping(address => uint256) public totalReceived; uint256 public contractBalance;
event DepositMade(address indexed user, uint256 amount, uint256 timestamp); event PaymentProcessed(address indexed from, address indexed to, uint256 amount);
function deposit() public payable { require(msg.value > 0, "Нужно отправить эфир");
deposits[msg.sender] += msg.value; totalReceived[msg.sender] += msg.value; contractBalance += msg.value;
emit DepositMade(msg.sender, msg.value, block.timestamp); }
function processPayment(address recipient, uint256 amount) public { require(deposits[msg.sender] >= amount, "Недостаточно средств"); require(recipient != address(0), "Неправильный адрес получателя");
deposits[msg.sender] -= amount; contractBalance -= amount;
payable(recipient).transfer(amount);
emit PaymentProcessed(msg.sender, recipient, amount); }
function getPaymentInfo(address user) public view returns ( uint256 currentDeposit, uint256 totalEverReceived, uint256 availableForWithdraw, uint256 userPercentageOfContract ) { currentDeposit = deposits[user]; totalEverReceived = totalReceived[user]; availableForWithdraw = deposits[user];
if (contractBalance > 0) { userPercentageOfContract = (deposits[user] * 100) / contractBalance; } else { userPercentageOfContract = 0; } }
// Специальная функция для приема эфира без вызова deposit() receive() external payable { // Автоматически зачисляем на депозит deposits[msg.sender] += msg.value; totalReceived[msg.sender] += msg.value; contractBalance += msg.value;
emit DepositMade(msg.sender, msg.value, block.timestamp); }}contract FunctionAnalyzer { struct FunctionCall { bytes4 selector; address caller; uint256 timestamp; uint256 dataLength; bytes data; }
mapping(bytes4 => uint256) public functionCallCounts; mapping(bytes4 => string) public functionNames; FunctionCall[] public functionCalls;
event FunctionCalled(bytes4 indexed selector, address indexed caller, uint256 dataLength);
constructor() { // Регистрируем названия функций для удобства functionNames[this.analyzeCall.selector] = "analyzeCall"; functionNames[this.getCallHistory.selector] = "getCallHistory"; functionNames[this.getMostCalledFunction.selector] = "getMostCalledFunction"; }
function analyzeCall(uint256 number, string memory text) public { // Анализируем текущий вызов bytes4 selector = msg.sig;
functionCallCounts[selector]++;
functionCalls.push(FunctionCall({ selector: selector, caller: msg.sender, timestamp: block.timestamp, dataLength: msg.data.length, data: msg.data }));
emit FunctionCalled(selector, msg.sender, msg.data.length);
// Логика функции // ... делаем что-то с number и text }
function getCallHistory(uint256 limit) public view returns ( bytes4[] memory selectors, address[] memory callers, uint256[] memory timestamps ) { uint256 length = functionCalls.length; if (limit > 0 && limit < length) { length = limit; }
selectors = new bytes4[](length); callers = new address[](length); timestamps = new uint256[](length);
for (uint256 i = 0; i < length; i++) { uint256 index = functionCalls.length - 1 - i; // Последние вызовы первыми selectors[i] = functionCalls[index].selector; callers[i] = functionCalls[index].caller; timestamps[i] = functionCalls[index].timestamp; } }
function getMostCalledFunction() public view returns ( bytes4 mostCalledSelector, string memory functionName, uint256 callCount ) { bytes4[] memory allSelectors = new bytes4[](3); allSelectors[0] = this.analyzeCall.selector; allSelectors[1] = this.getCallHistory.selector; allSelectors[2] = this.getMostCalledFunction.selector;
uint256 maxCalls = 0;
for (uint256 i = 0; i < allSelectors.length; i++) { if (functionCallCounts[allSelectors[i]] > maxCalls) { maxCalls = functionCallCounts[allSelectors[i]]; mostCalledSelector = allSelectors[i]; } }
functionName = functionNames[mostCalledSelector]; callCount = maxCalls; }
function decodeCallData() public view returns ( bytes4 selector, bytes memory parameters ) { selector = bytes4(msg.data[:4]); parameters = msg.data[4:]; }}contract GasAnalyzer { struct GasSnapshot { uint256 gasPrice; uint256 timestamp; address caller; bytes4 functionSelector; }
GasSnapshot[] public gasHistory; uint256 public totalGasSpent; mapping(address => uint256) public userGasSpent;
event GasPriceRecorded(uint256 gasPrice, uint256 timestamp, address caller);
function recordGasPrice() public { gasHistory.push(GasSnapshot({ gasPrice: tx.gasprice, timestamp: block.timestamp, caller: msg.sender, functionSelector: msg.sig }));
// Оцениваем потраченный газ (примерно) uint256 estimatedGasUsed = 21000; // Базовая стоимость транзакции uint256 gasCost = estimatedGasUsed * tx.gasprice;
totalGasSpent += gasCost; userGasSpent[msg.sender] += gasCost;
emit GasPriceRecorded(tx.gasprice, block.timestamp, msg.sender); }
function getGasAnalytics() public view returns ( uint256 averageGasPrice, uint256 minGasPrice, uint256 maxGasPrice, uint256 totalSnapshots ) { require(gasHistory.length > 0, "Нет данных о газе");
uint256 total = 0; minGasPrice = gasHistory[0].gasPrice; maxGasPrice = gasHistory[0].gasPrice;
for (uint256 i = 0; i < gasHistory.length; i++) { uint256 gasPrice = gasHistory[i].gasPrice; total += gasPrice;
if (gasPrice < minGasPrice) minGasPrice = gasPrice; if (gasPrice > maxGasPrice) maxGasPrice = gasPrice; }
averageGasPrice = total / gasHistory.length; totalSnapshots = gasHistory.length; }
function isGasPriceOptimal() public view returns ( bool isOptimal, string memory recommendation ) { uint256 currentGasPrice = tx.gasprice;
if (gasHistory.length == 0) { return (true, "No historical data"); }
(, , uint256 maxGasPrice, ) = getGasAnalytics();
if (currentGasPrice > maxGasPrice * 2) { isOptimal = false; recommendation = "Gas price too high, consider waiting"; } else if (currentGasPrice < maxGasPrice / 2) { isOptimal = true; recommendation = "Excellent gas price"; } else { isOptimal = true; recommendation = "Normal gas price"; } }}contract ReputationSystem { struct UserReputation { uint256 score; uint256 lastActivityBlock; uint256 totalTransactions; uint256 totalValueTransferred; uint256 averageGasPrice; bool isActive; mapping(bytes4 => uint256) functionCallCounts; }
mapping(address => UserReputation) public reputations; uint256 public constant REPUTATION_DECAY_BLOCKS = 28800; // ~4 дня
event ReputationUpdated(address indexed user, uint256 newScore, uint256 blockNumber);
function updateReputation() public payable { UserReputation storage rep = reputations[msg.sender];
// Проверяем активность uint256 blocksSinceLastActivity = block.number - rep.lastActivityBlock;
if (blocksSinceLastActivity > REPUTATION_DECAY_BLOCKS) { // Репутация ухудшается при долгом отсутствии rep.score = rep.score * 90 / 100; // -10% }
// Улучшаем репутацию за активность rep.score += 10;
// Бонус за отправку эфира if (msg.value > 0) { rep.score += msg.value / 1 ether; rep.totalValueTransferred += msg.value; }
// Учитываем цену газа (более высокая цена = больше приоритет) if (tx.gasprice > 20 gwei) { rep.score += 5; // Бонус за высокую цену газа }
// Обновляем статистику rep.lastActivityBlock = block.number; rep.totalTransactions++; rep.functionCallCounts[msg.sig]++; rep.isActive = true;
// Обновляем среднюю цену газа rep.averageGasPrice = (rep.averageGasPrice * (rep.totalTransactions - 1) + tx.gasprice) / rep.totalTransactions;
emit ReputationUpdated(msg.sender, rep.score, block.number); }
function getReputation(address user) public view returns ( uint256 currentScore, uint256 adjustedScore, string memory status, uint256 totalTx, uint256 avgGasPrice ) { UserReputation storage rep = reputations[user]; currentScore = rep.score; totalTx = rep.totalTransactions; avgGasPrice = rep.averageGasPrice;
// Вычисляем актуальную репутацию с учётом времени uint256 blocksSinceActivity = block.number - rep.lastActivityBlock;
if (blocksSinceActivity > REPUTATION_DECAY_BLOCKS) { adjustedScore = currentScore * 90 / 100; status = "Inactive"; } else { adjustedScore = currentScore; status = "Active"; } }
function getTopUsers(uint256 count) public view returns ( address[] memory users, uint256[] memory scores ) { // Упрощенная реализация - в реальности нужна более сложная сортировка users = new address[](count); scores = new uint256[](count);
// Здесь должна быть логика поиска топ-пользователей // Для примера просто возвращаем пустые массивы }}// ❌ УЯЗВИМЫЙ контракт Алексаcontract AlexLottery { address public owner; uint256 public ticketPrice = 0.1 ether; address[] public players; uint256 public gameEndTime;
constructor() { owner = msg.sender; gameEndTime = block.timestamp + 1 hours; }
function buyTicket() public payable { require(msg.value == ticketPrice, "Неправильная цена билета"); require(block.timestamp < gameEndTime, "Игра завершена");
players.push(msg.sender); }
// УЯЗВИМАЯ функция function drawWinner() public { require(block.timestamp >= gameEndTime, "Игра ещё не завершена"); require(players.length > 0, "Нет участников");
// "Случайный" выбор - УЯЗВИМОСТЬ! uint256 randomIndex = uint256(blockhash(block.number - 1)) % players.length;
address winner = players[randomIndex]; uint256 prize = address(this).balance;
delete players; gameEndTime = block.timestamp + 1 hours;
payable(winner).transfer(prize); }}// ✅ Более безопасная версия (но все еще не идеальная)contract SaferLottery { address public owner; uint256 public ticketPrice = 0.1 ether; address[] public players; uint256 public gameEndTime; uint256 private nonce = 0;
// Используем множество источников энтропии function drawWinner() public { require(block.timestamp >= gameEndTime, "Игра ещё не завершена"); require(players.length > 0, "Нет участников");
// Комбинируем несколько источников случайности uint256 randomSeed = uint256(keccak256(abi.encodePacked( blockhash(block.number - 1), blockhash(block.number - 2), block.timestamp, block.difficulty, msg.sender, nonce, players.length )));
uint256 randomIndex = randomSeed % players.length; nonce++; // Увеличиваем nonce для следующего использования
address winner = players[randomIndex]; uint256 prize = address(this).balance;
delete players; gameEndTime = block.timestamp + 1 hours;
payable(winner).transfer(prize); }}msg.sender)msg.value)msg.data, msg.sig)tx.gasprice)blockhash())block.difficulty, block.gaslimit)block.coinbase)tx.origin для авторизацииblockhash() (только 256 блоков)

