Skip to content

Account Abstraction với ERC-4337 (Part 4): Aggregate Signatures

Posted on:April 7, 2023

Intro

Hiện tại ta đang thực hiện validate riêng rẽ mỗi op có trong bundle. Điều này có thể dẫn đến lãng phí gas, vì check signature là một việc khá tốn gas khi nó phải thực hiện rất nhiều những phép toán mã hóa.

Chẳng phải là tốt hơn nếu ta có thể validate nhiều op cùng một lúc với chỉ một signature thay vì nhiều signature hay không?

Câu trả lời là có thể, dựa trên một concept trong mã hóa là aggregate signatures.

Một mô hình chữ kí (signature scheme) có hỗ trợ aggregation sẽ có khả năng kết hợp nhiều chữ ký được kí bởi những key khác nhau để tạo ra một chữ ký duy nhất; nếu chữ ký duy nhất này được xác nhận là hợp lệ thì cũng có nghĩa là tất cả những chữ ký khác cũng là hợp lệ.

Một ví dụ của mô hình chữ kí này là BLS.

Việc tối ưu này đặc biệt hữu ích với các hệ thống rollup, vì mục đích chính của rollup là nén dữ liệu, nên nén chữ ký là rất cần thiết.

Bạn đọc có thể tham khảo thêm về việc tiết kiệm đạt được khi dùng signatures aggregation qua Tweet này của Vitalik.

Giới thiệu aggregator

Không phải tất cả các op trong một bundle đều có chữ ký có thể tiến hành aggregate. Nên nhớ rằng wallet có thể sử dụng bất cứ cách nào để xác thực chữ ký của user trong operation, và có thể có rất nhiều những mô hình chữ ký khác nhau trong cùng một bundle.

Do ta không thể aggregate các chữ ký sử dụng những mô hình khác nhau, nên sau cùng sau khi tiến hành aggregate các op trong bundle, ta sẽ thu được các nhóm operation, mỗi nhóm sẽ gồm có các operation có chung signature scheme.

Chúng ta cũng sẽ cần phải có nhiều on-chain aggregation scheme với logic riêng của nó, mỗi mô hình sẽ được đại diện bởi một contract mà chúng ta sẽ gọi là aggregator.

Mỗi mô hình aggregation được định nghĩa bởi cách mà nó kết hợp nhiều chữ ký lại làm một và cách làm thế nào mà nó có thể validate chữ ký kết hợp đó, khi này interface của aggregator sẽ có các hàm như sau:

contract Aggregator {
  function aggregateSignatures(UserOperation[] ops)
    returns (bytes aggregatedSignature);

  function validateSignatures(UserOperation[] ops, bytes signature);
}

aa-08

Do mỗi wallet có thể tự do định nghĩa mô hình xác thực chữ ký của nó, nó cũng có thể tự do lựa chọn aggregator mà nó tương thích.

Nếu một wallet muốn chữ kí có thể aggregate, nó sẽ cần chỉ rõ aggregator của nó:

contract Wallet {
  // ...

  function getAggregator() returns (address);
}

Khi này bằng cách sử dụng getAggregator, bundler hoàn toàn có thể nhóm những operation có chung aggregator lại sau đó gọi hàm aggregateSignatures trên aggregator để kết hợp các chữ ký trong các op đó lại với nhau.

Một group sẽ trông thế này:

struct UserOpsPerAggregator {
  UserOperation[] ops;
  address aggregator;
  bytes combinedSignature;
}

Nếu một bundler có off-chain knowledge về cách một aggregator cụ thể nào đó chạy, nó hoàn toàn có thể tối ưu hóa quá trình aggregate chữ kí bằng cách sử dụng hardcode thuật toán aggregation đó luôn, thay vì phải chạy aggregateSignatures như EVM code.

Tiếp theo ta cần update Entry Point để sử dụng với aggregator mới.

Ta sẽ thêm vào trong Entry Point một phương thức mới, handleAggregateOps, hoạt động giống như handleOps nhưng đầu vào sẽ là những nhóm op có chữ kí đã được kết hợp bởi aggregator:

contract EntryPoint {
  function handleOps(UserOperation[] ops);

	function handleAggregatedOps(UserOpsPerAggregator[] ops);

  // ...
}

hàm handleAggregatedOps này hoạt động hầu như giống với handleOps, ngoại trừ bước validation mà thôi.

Trong khi handleOps thực hiện validate bằng cách gọi hàm validateOp ở mỗi wallet, thì handleAggregatedOps sẽ gọi validateSignatures ở mỗi aggregator trên mỗi nhóm.

aa-09

Chúng ta đã hầu như hoàn thiện kiến trúc của ERC-4337, chỉ còn một vấn đề nho nhỏ mà ta đã quen thuộc: sự khác biệt giữa simulation và chạy thực tế.

Bundler sẽ muốn simulate việc validation và chắc chắn rằng aggregator sẽ validate chữ kí kết hợp của nhóm trước khi đưa các op của nhóm vào trong bundle, vì nếu validation mà fail thì bundler sẽ phải tự trả phí mà không nhận được lại đồng nào. Nhưng logic validate của aggregator phụ thuộc hoàn toàn vào chính aggregator mà thôi, nên sẽ có xác xuất simulation success mà khi chạy thực tế lại fail.

Ta sẽ giải quyết vấn đề quen thuộc này bằng giải pháp quen thuộc mà ta đã làm với paymasterfactory: giới hạn storage mà aggregator có thể truy cập, đồng thời yêu cầu aggregator join vào reputation system bằng cách stake ETH vào trong Entry Point (ngoại lệ tương tự: nếu validation không truy cập aggregator associated storage thì không cần stake).

Và đó là tất cả về aggregate signatures!

Wrap up

Giờ đây ta đã có toàn bộ kiến thức về kiến trúc của ERC-4337, ta có thể tham khảo thêm về đề xuất gốc của ERC-4337. Có thể sẽ có vài chi tiết khác biệt đôi chút về tên hàm hay biến, nhưng nội dung bao trùm về cơ bản là giống nhau.

Hoặc ta có thể nhảy luôn vào code với các phiên bản đã và đang được phát triển của ERC-4337:

Tham khảo