5 个版本
0.1.5 | 2023 年 8 月 21 日 |
---|---|
0.1.4 | 2023 年 8 月 21 日 |
0.1.3 | 2023 年 8 月 21 日 |
0.1.1 | 2023 年 8 月 21 日 |
0.1.0 | 2023 年 8 月 21 日 |
#2313 在 魔法豆
29KB
370 行
Timeboost-rs
此库实现了 时间提升排序策略,用于 Rust 中的区块链交易。
该协议由 @OffchainLabs 研究员 Akaki Mamageishvili、Mahimna Kelkar、Ed Felten 和伦敦大学 Jan Christoph Schlegel 编写的名为 "购买时间:延迟竞赛与交易排序竞标" 的研究论文所描述。此 crate 中实现的所有想法都是上述研究的结果。
时间提升是一种对交易进行公平排序的方法,它考虑时间戳和竞标来创建一个分数,该分数可以用于对 rollup 序列化器进行排序。它支持低延迟最终性,类似于先到先得,但对用户更加公平。有了时间提升,竞标可以帮助在最终排序中购买时间,但最多只能购买一个常数因子 G
(以毫秒为单位)。
此库包含 Rust 代码,定义了一个异步的 TimeBoostService
,可以通过输入通道接收交易,并通过在内部应用协议,持续输出最终排序列表。此实现是时间提升协议的“离散”版本,因为它在时间 G
的轮次中运行。以下是它的工作原理:
- 记录初始时间戳,
T
- 在后台接收交易,将它们推送到按竞标排序的优先队列中(如果有时间戳相同的情况,则按最早到达时间戳解决冲突)
- 在时间
T+G
,其中G
是定义在毫秒中的常数,所有在优先队列中的交易都将被释放,并且它们的时戳将被修改为它们在输出流中发射的时间。 - 从
T = T_now
重新开始计数,直到下一轮
感谢 Ed Felten 提出的想法。
依赖项
Rust 稳定版本 1.71.1
使用方法
使用此库的主要方法是使用一个事务输出通道初始化 TimeBoostService
结构体。
use timeboost_rs::TimeBoostService;
use tokio::sync::broadcast;
let (tx_output_feed, mut rx) = broadcast::channel(100);
let mut service = TimeBoostService::new(tx_output_feed);
可以通过选项配置服务,以自定义最大提升因子 G
或事务输入通道的容量。
let mut service = TimeBoostService::new(tx_output_feed)
.input_feed_buffer_capacity(1000)
.g_factor(200 /* millis */);
放入此服务的事务类型为 BoostableTx
,它是由三个字段组成的简单结构体。
pub struct BoostableTx {
pub id: u64,
pub bid: u64,
pub timestamp: NaiveDateTime,
}
BoostableTx
根据 时间提升规范实现了 Ord
特性,这意味着它们按最大出价排序,出价相同的情况下按最早时间戳作为平局决定。要使用自定义事务类型与 TimeBoostService
一起使用,为您自己的类型实现 From
特性。
以下是一个使用时间提升、向其中发送事务以及接收输出的完整示例。
use timeboost_rs::{TimeBoostService, BoostableTx};
use tokio::sync::broadcast;
#[tokio::main]
async fn main() {
let (tx_output_feed, mut rx) = broadcast::channel(100);
let mut service = TimeBoostService::new(tx_output_feed);
// Obtain a channel handle to send txs to the TimeBoostService.
let sender = service.sender();
// Spawn a dedicated thread for the time boost service.
std::thread::spawn(move || service.run());
let mut txs = vec![
BoostableTx::new(0 /* id */, 1 /* bid */, 100 /* unix timestamp millis */),
BoostableTx::new(1 /* id */, 100 /* bid */, 101 /* unix timestamp millis */),
];
// Send the txs to the time boost service.
for tx in txs.iter() {
sender.send(tx.clone()).unwrap();
}
// Await receipt of both txs from the timeboost service's output feed.
let mut got_txs = vec![];
for _ in 0..2 {
let tx = rx.recv().await.unwrap();
got_txs.push(tx);
}
// Assert we received 2 txs from the output feed.
assert_eq!(txs.len(), 2);
// Assert the output is the same as the reversed input, as
// the highest bid txs will be released first.
txs.reverse();
let want = txs.into_iter().map(|tx| tx.id).collect::<Vec<_>>();
let got = got_txs.into_iter().map(|tx| tx.id).collect::<Vec<_>>();
assert_eq!(want, got);
}
度量指标
该库公开了一个 TIME_BOOST_ROUNDS_TOTAL
prometheus 计数器,用于检查经过的轮数。
lazy_static! {
static ref TIME_BOOST_ROUNDS_TOTAL: IntCounter = register_int_counter!(
"timeboost_rounds_total",
"Number of time boost rounds elapsed"
)
.unwrap();
}
许可证
根据您的选择,在 Apache 许可证 2.0 版 或 MIT 许可证 下授权。
除非您明确声明,否则根据 Apache-2.0 许可证定义的,您有意提交的任何贡献,均应按上述方式双重许可,不附加任何额外条款或条件。
依赖项
~6–13MB
~147K SLoC