Читайте на GitHub: https://github.com/loredanacirstea/articles/blob/master/articles/Taylor-EVM_compiled.md

Тейлор начинал как интерпретируемый функциональный язык для EVM, рожденный в рамках нашего проекта Конвейер. Pipeline — это текстовый и визуальный язык для программирования на основе потока, в котором входы и выходы функций могут быть связаны для создания сложных атомарных операций. Эти атомарные операции интерпретируются нашим смарт-контрактом интерпретатора конвейерных графов, или графы могут быть развернуты как автономные смарт-контракты, оптимизированные для меньших затрат на транзакционный газ.

Вместе с Тейлором мы создали полный по Тьюрингу язык, который может интерпретироваться EVM, с операциями, которые могут выполняться как в стеке, так и во фреймах памяти. Это позволяет Тейлору выполнять рекурсивные операции, которые сейчас невозможны на Solidity или Юл (язык, на котором основана Solidity) (https://github.com/ethereum/solidity/issues/9622).

Например, Тейлор может интерпретировать эту рекурсивную реализацию ряда Фибоначчи с большим количеством итераций (ограниченным лимитом газа, а не лимитом стека), потому что, в отличие от Solidity или Yul, он может оставлять стек пустым между вызовами функций:

(def! fibonacci (fn* (n) (if (or (eq n 1) (eq n 2)) 1 (add(fibonacci (sub n 1)) (fibonacci (sub n 2)) ) )))

При создании интерпретатора Taylor и других интерпретаторов EVM ни Solidity, ни Yul не были достаточно гибкими, чтобы создавать их эффективно. Именно для этого мы создали макроязык — mASM. mASM производит сборку EVM.

Сегодня мы объявляем о следующем шаге Тейлора: в качестве компилируемого языка.

taylor-evm — это промежуточный язык, который дает разработчикам доступ ко всем инструкциям EVM и к нескольким готовым композициям. Он компилируется в байт-код EVM, который можно использовать как смарт-контракт. Он заменяет mASM.

Его каноническая форма выглядит как (add 34 (add 3 4)). Но он также имеет форму на основе отступов с необязательными скобками:

add
  34
  add
    3
    4

or

add
  34
  (add 3 4)

Вы можете напрямую управлять стеком:

(list 
  0x02
  0x04
  (dup 2)
  (swap 1)
  (add 5))

Вы можете получить доступ к потоку управления изменениями:

(if (eq 3 4) (add 0x03 0x04) (add 0x05 0x06))
switch 0x4444
    (case 0x1000 (add 0x1 0x1))
    (case 0x4444 (add 0x2 0x2))
    (case 0x2000 (add 0x3 0x3))
    (default 0x55)

Вы можете использовать петли. Ниже приведен эффективный нерекурсивный способ реализации функции Фибоначчи (fib):

(list
  0x00
  0x01
  (loop 1 8
    (list
      (add (dup 4) (dup 4))
      (swap 3)
      (swap 4)
      (pop)
    )
  )
  (mem-store 0x00)
  (return 0x00 0x20)
)

Следовательно, функцию Фибоначчи можно записать в виде смарт-контракта следующим образом:

define fib ["uint256"] ["uint256"] 
  if (eq 0x0 (dup 1))
    (pass 0x0)
    if (eq 0x1 (dup 1))
      (pass 0x01)
      list
        add
          (fib (sub (dup 4) 1 ))
          (fib (sub (dup 3) 2 ))
        (swap 1)
        (pop)
to-deploy 
  list
    (include "fib")
    (fib (calldata-load 0x0))
    (mem-store 0x00)
    (return 0x00 0x20)

Или, только с отступом, вот так:

if 
  eq
    0x1
    dup
      1
  pass
    0x01
  list
    add
      fib
        sub
          dup
            4
          1
      fib
        sub
          dup
            3
          2
    swap
      1
    pop

Сгенерированный ассемблерный код (asm):

0x4b
0x0d
0x00
codecopy
0x4b
0x00
return
stop
after_do_fib_14
0x00
calldataload
fib
jump
after_do_fib_14:
0x00
mstore
0x20
0x00
return
fib:
dup1
0x00
eq
ifsource_9
jumpi
elsesource_9:
dup1
0x01
eq
ifsource_8
jumpi
elsesource_8:
after_do_fib_13
0x02
dup3
sub
fib
jump
after_do_fib_13:
after_do_fib_12
0x01
dup4
sub
fib
jump
after_do_fib_12:
add
swap1
pop
endif_8
jump
ifsource_8:
fib_end
jump
endif_8:
endif_9
jump
ifsource_9:
fib_end
jump
endif_9:
fib_end:
swap1 
jump

Сравнение

Приведенный выше контракт функции Фибоначчи эквивалентен следующему контракту в Yul:

object "TestFib" {
  code {
    datacopy(0, dataoffset("Runtime"), datasize("Runtime"))
    return(0, datasize("Runtime"))
  }
  object "Runtime" {
    code {
      let input := calldataload(0x0)
      let res := fib(input)
      mstore(0x0, res)
      return(0x0, 0x20)
      function fib(nth) -> result {
        switch nth
        case 0 { result := 0 }
        case 1 { result := 1 }
        default {
          result := add(fib(sub(nth, 2)), fib(sub(nth, 1)))
}}}}}

На данном этапе это статистика от нашего собственного отладчика Cometh EVM при вызове fib(16), fib(18), fib(19), fib(30):

Производительность скомпилированного Taylor по сравнению с Yul составляет стабильные 94% по газу и 89,7% по шагам выполнения с более важным запасом по использованию стека.

Скомпилированные и интерпретированные

Скомпилированная версия Taylor выполняет те же сценарии использования, что и Solidity и Yul, — оптимизация для выполнения транзакций в EVM.

Интерпретированная версия Taylor оптимизирована для обеспечения гибкости, возможности обновления и обработки вне сети, что подтверждено EVM.

Насколько нам известно внутреннее устройство Solidity, скомпилированный код генерируется Yul: он основан на Yul. Если нам удалось превзойти Yul, это единственное сравнение, которое нам нужно: производительность Solidity будет равна или ниже, чем у Yul. Для достижения максимальной производительности нам пришлось напрямую использовать язык ассемблера EVM (ASM), и для этой цели нам пришлось разработать собственный макроязык: mASM. И интерпретируемый Тейлор основан на mAsm, в то время как скомпилированный Тейлор построен (используя себя) прямо из ASM. Taylor в настоящее время используется как язык, интерпретируемый EVM, компилируемый для EVM и интерпретируемый JavaScript. Поэтому разработчик может использовать один и тот же язык для разработки приложений web3 dApp. Однако среди трех разновидностей Taylor скомпилированная версия (которую мы демонстрировали сегодня) является наиболее недоработанной: ведется работа над управлением стеком и памятью с намерением превзойти нашу текущую реализацию.

Демонстрационное видео

Эта технология была создана волонтерами Laurel Project и для них. Вы можете присоединиться к этой технической инициативе: https://forms.gle/WmSaSbxhHiiA2qZV7. https://www.reddit.com/r/provable_laurel/.