Как объяснялось в моем предыдущем посте, мой первый смарт-контракт основан на примере Выход из контрактов из документации Solidity Common Patterns. В этом посте я рассмотрю часть кода Solidity, который я изучил.
Введение в смарт-контракт
Пример в документации был вдохновлен игрой King of the Ether, а правила контракта таковы:
- Для игры пользователь вводит сумму X Ether, оплаченную со своего адреса.
- Если X › историческийМаксимальный:
- пользователь король
- старый король может собирать предыдущие платежи
- исторический максимум = X
Сам договор это:
pragma solidity ^0.4.2; contract WithdrawalContract { address public richest; uint public mostSent; mapping (address => uint) pendingWithdrawals; function WithdrawalContract() payable { richest = msg.sender; mostSent = msg.value; } event BecameRichestEvent(address sender, uint amount); event FailedRichestEvent(address sender, uint amount); event Collected(uint amount); function BecomeRichest() payable returns (bool) { if (msg.value > mostSent) { pendingWithdrawals[richest] += msg.value; richest = msg.sender; mostSent = msg.value; BecameRichestEvent(msg.sender, msg.value); return true; } else { FailedRichestEvent(msg.sender, msg.value); return false; } } function withdraw() { uint amount = pendingWithdrawals[msg.sender]; // Remember to zero the pending refund before // sending to prevent re-entrancy attacks pendingWithdrawals[msg.sender] = 0; msg.sender.transfer(amount); Collected(amount); } }
Особенности твердости
Я нашел эту документацию Введение в смарт-контракты хорошим источником информации.
Адреса - адреса самых богатых людей;
Введите адрес — содержит 20-байтный адрес Ethereum. Здесь он используется для сохранения адреса пользователя, который на данный момент является самым богатым.
public
разрешает другим контрактам доступ к переменной.
Адрес имеет различные функции-члены, как подробно описано здесь. Одним из них является address.transfer(uint256 amount)
, который отправляет заданное количество Wei на адрес. В этом случае передача используется в функции вывода для безопасной отправки эфира на действительный адрес пользователя.
Mappings - mapping (address => uint) pendingWithdrawals;
Следующая строка, mapping (address => uint) public balances;
, также создает общедоступную переменную состояния, но это более сложный тип данных.
Отображения можно рассматривать как хеш-таблицы. PendinWithdrawals отображает адреса в беззнаковые целые числа. Например:
pendingWithdrawals[0xc7975434577b0d57248e1de03fcc6f27cd6cc742] = 7;
Сопоставляет значение 7 с адресом 0xc7975434577b0d57248e1de03fcc6f27cd6cc742 и может вызываться с помощью:
x = pendingWithdrawals[0xc7975434577b0d57248e1de03fcc6f27cd6cc742];
x = 7
Транзакции и конструкторы — функция WithdrawalContract() оплачивается
Это конструктор — функция, которая запускается при первом создании контракта.
Модификатор payable означает, что функция является транзакцией. Транзакция — это передача данных между двумя аккаунтами (хорошее объяснение здесь). Транзакция содержит некоторые стандартные данные, например. адрес отправителя или количество переводимых wei. Мы можем получить доступ к данным транзакции, используя глобальную переменную msg
.
В этом случае msg используется для установки начального самого богатого адреса на msg.sender, который является адресом человека, развертывающего контракт. Он также сохраняет mostSent как msg.value, который представляет собой количество сообщений, отправленных во время развертывания.
События — событие BecameRichestEvent(адрес отправителя, сумма не указана);
Внешний интерфейс приложения, в моем случае Web3.js, прослушивает запускаемые события Solidity, чтобы обновить интерфейс. Например, событие BecameRichest срабатывает, когда новая учетная запись становится самой богатой.
Событие запускается строкой:
BecameRichestEvent(msg.sender, msg.value);
Слушатель будет иметь доступ к отправителю и данным значения, переданным в вызов.
В следующем посте я планирую подробно описать некоторые функциональные возможности внешнего интерфейса, в том числе то, как прослушивать события.