📝 Web Assembly на EOS - 50 000 переводов в секунду (перевод статьи @dantheman)
Мы всегда старались использовать для написания контрактов EOS маленький простой язык, и изначально наш выбор пал на Wren. Несколько недель назад я провел тест на пустом контракте. Он показал производительность около 1000 транзакций в секунду, что слишком медленно для нашей цели.
В последние пару недель команда разработчиков EOS отошла от языка программирования Wren и начала использовать Web Assembly. Сегодня мы хотели бы рассказать вам о нашем прогрессе и первых результатах, которых мы достигли.
Немного о Web Assembly
Web Assembly - это новый стандарт индустрии, поддерживаемый Microsoft, Google и Apple. Цель этого стандарта - дать возможность запускать не требующий доверия высокопроизводительный код в вашем браузере. Web Assembly стремительно меняет правила игры, делая возможным создание высокопроизводительных веб-приложений, таких как видео- и фоторедакторы и игры.
WebAssembly предоставляет универсальную цель компиляции, что позволяет разрабатывать приложения на любом языке. На данный момент есть компиляторы для C, C++ и Rust. Также ведется работа над компиляцией Solidity на Web Assembly.
Интеграция EOS
Несколько недель назад мы представили смарт-контракт гипотетической валюты, написанный на Wren. Сегодня же мы продемонстрируем настоящую работающую версию, написанную на "C" и скомпилированную на Web Assembly (WASM). Затем мы использовали транзакции EOS, чтобы создать аккаунт (@simplecoin) и загрузить код WASM в тестовый блокчейн.
На этом этапе развития пока что всё находится в стремительном движении, и есть некоторые шероховатости, которые будут сглажены перед запуском нашей официальной публичной тестовой сети этим летом. Например, определения сообщений и десериализационный шаблон могут быть заменены простым генератором кода, который принимает входные данные схоже с нашим гипотетическим примером.
Тем не менее, вот пример того, как выглядит контракт на C сегодня:
typedef struct {
AccountName from;
AccountName to;
uint64_t amount;
String* memo;
} Transfer;
void Transfer_unpack( DataStream* ds, Transfer* transfer )
{
AccountName_unpack( ds, &transfer->from );
AccountName_unpack( ds, &transfer->to );
uint64_unpack( ds, &transfer->amount );
String_unpack( ds, &transfer->memo );
}
typedef struct {
uint64_t balance;
} Balance;
/** Constructor called once when code is first uploaded */
void onInit() {
static Balance initial;
static AccountName simplecoin;
AccountName_initCString( &simplecoin, "simplecoin", 10 );
initial.balance = 1000*1000;
store( &simplecoin, sizeof(AccountName), &initial, sizeof(Balance));
}
/** Message handler when Transfer message is delivered to @simplecoin */
void onApply_Transfer_simplecoin() {
static char buffer[100];
int read = readMessage( buffer, 100 ); /** load message content */
static Transfer message;
static DataStream ds;
DataStream_init( &ds, buffer, read );
Transfer_unpack( &ds, &message ); /* unpack it */
static Balance from_balance;
static Balance to_balance;
to_balance.balance = 0;
read = load( &message.from, sizeof(message.from),
&from_balance.balance, sizeof(from_balance.balance) );
assert( read == sizeof(Balance), "no existing balance" );
assert( from_balance.balance >= message.amount, "insufficient funds" );
load( &message.to, sizeof(message.to),
&to_balance.balance, sizeof(to_balance.balance) );
to_balance.balance += message.amount;
from_balance.balance -= message.amount;
if( from_balance.balance )
store( &message.from, sizeof(AccountName),
&from_balance.balance, sizeof(from_balance.balance) );
else
remove( &message.from, sizeof(AccountName) );
store( &message.to, sizeof(message.to),
&to_balance.balance, sizeof(to_balance.balance) );
}
Этот код был скомпилирован с использованием интерфейса WasmFiddle для генерации WebAssembly (WASM). Он использует несколько простых вызовов API, таких как readMessage
, load
и store
, для извлечения и хранения информации из блокчейна.
Конкретно этот контракт создаст 1 млн монет и разместит их на аккаунте @simplecoin, а потом позволит ему перевести эти монеты на другие аккаунты, которые в свою очередь смогут передать их другим.
Первоначальные контрольные показатели
Я создал тестовый юнит, который загрузит этот контракт и затем сконструирует индивидуальные транзакции, чтобы перевести средства с @simplecoin на @init1 1000 раз.
auto start = fc::time_point::now();
for( uint32_t i = 0; i < 1000; ++i )
{
eos::chain::SignedTransaction trx;
trx.emplaceMessage("simplecoin", "simplecoin",
vector<AccountName>{"init1"}, "Transfer",
types::Transfer{"simplecoin", "init1", 1+i, "memo"} );
trx.expiration = db.head_block_time() + 100;
trx.set_reference_block(db.head_block_id());
db.push_transaction(trx);
}
auto end = fc::time_point::now();
idump(( 1000*1000000.0 / (end-start).count() ) );
Конечный результат дал средний показатель в примерно 50 000 переводов в секунду по многим различным запускам. Имейте в виду, что в этих ранних результатах полно вещей, которые влияют на производительность в лучшую и худшую сторону. Пока слишком рано делать выводы о конечной производительности цепи, но 50 000 последовательных действий в секунду - это намного ближе к области, в которой мы хотим быть - Facebook, Visa, и так далее.
Производительность была измерена на iMac 2014 с процессором Intel Core i7 с частотой 4 ГГц.
Сравнение с Wren
Причина, по которой Wren был медленнее, заключалась в том, что ему приходилось компилировать код каждый раз, и не было простого способа кэшировать скомпилированные результаты. Оказывается, скорость Wren сильно зависит от работы программы в течение длительного периода времени по сравнению с ее начальной стоимостью запуска. Это противоположность тому, чего мы хотим для платформы смарт-контрактов, которая поддерживает множество быстрых программ.
Библиотека WebAssembly, которую мы используем, компилирует Web Assembly (WASM) в нативные инструкции x86, используя библиотеку компилятора LLVM. Это позволяет WASM работать со скоростью до 80% от изначальной скорости, что намного быстрее, чем любой интерпретируемый язык, и, конечно, еще быстрее, если оптимизация компиляции Just-in-Time (JIT) срабатывает в каждом отдельном запуске.
Движение вперед
Теперь, когда мы доказали состоятельность концепции контрактов на основе WebAssembly и подтвердили, что их однопоточная производительность уже лидирует в отрасли, мы продолжим дорабатывать API, которые публикуем для Web Assembly, и рассмотрим возможность добавления поддержки языков и инструментов более высокого уровня, чтобы сделать всё это удобнее для разработчиков, чем написание на C.
Наши первоначальные тестовые сети будут сосредоточены на стабильности кода и API и будут выполнять контракты в рамках одного потока.
Однако, дизайн архитектуры программного обеспечения EOS.IO позволит нам переключиться на многопоточное выполнение без необходимости производить хардфорк цепи. Как видно из наших первоначальных контрольных показателей, даже однопоточная реализация EOS по-прежнему способна быть лидером в отрасли с большим запасом для современных приложений.
Будьте в курсе
Подпишитесь на нашу рассылку на https://eos.io, чтобы получать информацию о последних разработках и готовящейся продаже токенов EOS.
Свежие новости в Телеграм: t.me/EOS_RU
Оригинал поста: ЗДЕСЬ