เฮ้ ฮับ!
ในเครือข่าย Bitcoin โหนดทั้งหมดตกลงร่วมกันในชุด UTXO: มีเหรียญจำนวนเท่าใดที่สามารถใช้ได้ ใครบ้าง และภายใต้เงื่อนไขใด ชุด UTXO คือชุดข้อมูลขั้นต่ำที่จำเป็นสำหรับโหนดตัวตรวจสอบความถูกต้อง โดยที่โหนดจะไม่สามารถตรวจสอบความถูกต้องของธุรกรรมขาเข้าและบล็อกที่มีธุรกรรมเหล่านั้นได้
ในเรื่องนี้ มีความพยายามทุกวิถีทางเพื่อลดการแสดงข้อมูลที่จัดเก็บไว้ของชุดนี้ เพื่อบีบอัดโดยไม่สูญเสียการรับประกันความปลอดภัย ยิ่งปริมาณข้อมูลที่จัดเก็บมีขนาดเล็กลง ความต้องการพื้นที่ดิสก์ของโหนดตัวตรวจสอบความถูกต้องก็จะน้อยลง ซึ่งทำให้การเปิดใช้งานโหนดตัวตรวจสอบความถูกต้องมีราคาถูก ช่วยให้คุณสามารถขยายเครือข่ายและเพิ่มความเสถียรของเครือข่ายได้
ในโพสต์นี้ เราจะโพสต์ต้นแบบของข้อเสนอล่าสุดจากผู้เขียนร่วมของ Rust
อะไรคือปัญหา?
ปัญหาหนึ่งที่เกิดขึ้นมายาวนานของ Bitcoin คือความสามารถในการขยายขนาดได้ แนวคิดของ "ธนาคารของคุณเอง" กำหนดให้ผู้เข้าร่วมเครือข่ายต้องเก็บบันทึกเงินทุนทั้งหมดที่มีอยู่ ใน Bitcoin เงินทุนที่มีอยู่จะแสดงเป็นชุดของผลลัพธ์ที่ยังไม่ได้ใช้ - ชุด UTXO แม้ว่านี่จะไม่ใช่การนำเสนอตามสัญชาตญาณโดยเฉพาะ แต่ก็มีประโยชน์ในแง่ของประสิทธิภาพการใช้งานมากกว่าการนำเสนอโดยที่ "กระเป๋าเงิน" แต่ละอันมี "ยอดคงเหลือ" เป็นรายการแยกต่างหาก และยังเพิ่มความเป็นส่วนตัว (เช่น
สิ่งสำคัญคือต้องแยกแยะระหว่างประวัติการทำธุรกรรม (สิ่งที่เรียกว่าบล็อคเชน) และสถานะปัจจุบันของระบบ ปัจจุบันประวัติการทำธุรกรรม Bitcoin ใช้พื้นที่ดิสก์ประมาณ 200 GB และยังคงเติบโตอย่างต่อเนื่อง อย่างไรก็ตาม สถานะของระบบจะเล็กกว่ามาก โดยมีขนาดประมาณ 4 GB และคำนึงถึงความจริงที่ว่าปัจจุบันมีคนเป็นเจ้าของเหรียญเท่านั้น ปริมาณของข้อมูลนี้ยังเพิ่มขึ้นเมื่อเวลาผ่านไป แต่ในอัตราที่ช้ากว่ามากและบางครั้งก็มีแนวโน้มลดลงด้วยซ้ำ (ดู CDPV)
Light Client (SPV) รับประกันความปลอดภัยทางการค้าสำหรับความสามารถในการจัดเก็บไม่มีสถานะขั้นต่ำ (ชุด UTXO) นอกเหนือจากคีย์ส่วนตัว
ชุด UTXO และ UTXO
UTXO (Unspent Transaction Output) คือเอาท์พุตธุรกรรมที่ยังไม่ได้ใช้ ซึ่งเป็นจุดสิ้นสุดของการเดินทางของ Satoshi แต่ละรายการที่ถ่ายโอนในธุรกรรม ผลลัพธ์ที่ยังไม่ได้ใช้จะกลายเป็นอินพุตของธุรกรรมใหม่ และจะถูกใช้ (ใช้จ่าย) และลบออกจากชุด UTXO
UTXO ใหม่จะถูกสร้างขึ้นตามธุรกรรมเสมอ:
- ธุรกรรม coinbase ที่ไม่มีอินพุต: สร้าง UTXO ใหม่เมื่อนักขุดออกเหรียญ
- ธุรกรรมปกติ: สร้าง UTXO ใหม่ในขณะที่ใช้ UTXO ที่มีอยู่บางชุด
กระบวนการทำงานร่วมกับ UTXO:
กระเป๋าเงินจะนับจำนวนเหรียญที่สามารถใช้จ่ายได้ (ยอดคงเหลือ) ตามจำนวน UTXO ที่มีอยู่ในกระเป๋าเงินนี้เพื่อการใช้จ่าย
โหนดเครื่องมือตรวจสอบแต่ละโหนดจะต้องตรวจสอบชุดเพื่อป้องกันการใช้จ่ายซ้ำซ้อน ทั้งหมด UTXO เมื่อตรวจสอบ แต่ละ ธุรกรรม แต่ละ ปิดกั้น.
โหนดจะต้องมีตรรกะ:
- นอกเหนือจากชุด UTXO
- การลบออกจากชุด UTXO
- การตรวจสอบการมีอยู่ของ UTXO เดียวในชุด
มีหลายวิธีในการลดข้อกำหนดสำหรับข้อมูลที่เก็บไว้เกี่ยวกับชุดหนึ่ง ในขณะที่ยังคงรักษาความสามารถในการเพิ่มและลบองค์ประกอบ ตรวจสอบและพิสูจน์การมีอยู่ขององค์ประกอบในชุดโดยใช้
แบตเตอรี่สำหรับ UTXO
แนวคิดในการใช้แบตเตอรี่เพื่อจัดเก็บ UTXO หลายตัว
ชุด UTXO ถูกสร้างขึ้นทันทีระหว่างการดาวน์โหลดบล็อกเริ่มต้น (IBD) โดยจัดเก็บแบบเต็มและถาวร ในขณะที่เนื้อหามีการเปลี่ยนแปลงหลังจากประมวลผลธุรกรรมจากแต่ละบล็อกใหม่และถูกต้องของเครือข่าย กระบวนการนี้จำเป็นต้องดาวน์โหลดข้อมูลบล็อกประมาณ 200 GB และยืนยันลายเซ็นดิจิทัลหลายร้อยล้านรายการ หลังจากกระบวนการ IBD เสร็จสิ้น สิ่งสำคัญคือชุด UTXO จะกินพื้นที่ประมาณ 4 GB
อย่างไรก็ตาม สำหรับนักสะสม กฎของฉันทามติสำหรับกองทุนจะลดลงเหลือเพียงการตรวจสอบและการสร้างหลักฐานการเข้ารหัส และภาระในการติดตามเงินทุนที่มีอยู่จะเปลี่ยนไปเป็นของเจ้าของกองทุนเหล่านั้น ซึ่งเป็นผู้แสดงหลักฐานการดำรงอยู่และความเป็นเจ้าของ
ตัวสะสมสามารถเรียกได้ว่าเป็นตัวแทนขนาดกะทัดรัดของชุด ขนาดของการแสดงที่เก็บไว้ต้องเป็นค่าคงที่ หรือเพิ่มขึ้นแบบใต้เชิงเส้นโดยคำนึงถึงจำนวนเชิงการนับของเซตและขนาดขององค์ประกอบเอง ตัวอย่างเช่น โดยที่ n คือภาวะเชิงการนับของเซตที่เก็บไว้
ในกรณีนี้ ตัวสะสมควรอนุญาตให้สร้างหลักฐานการรวมองค์ประกอบไว้ในชุด (หลักฐานการรวม) และทำให้สามารถตรวจสอบหลักฐานนี้ได้อย่างมีประสิทธิภาพ
แบตเตอรี่มีชื่อว่า พลวัต if อนุญาตให้คุณเพิ่มองค์ประกอบและลบองค์ประกอบออกจากชุด
ตัวอย่างของแบตเตอรี่ดังกล่าวจะเป็น
ยูทรีโซ
การออกแบบ Utreexo ที่เสนอโดย Thaddeus Dryja ทำให้สามารถสร้างได้ พลวัต аккумулятор ไม่มี ที่เชื่อถือได้-การตั้งค่า
Utreexo เป็นป่าแห่งไบนารีที่สมบูรณ์แบบ
โครงสร้างลอจิคัลของแบตเตอรี่
เซลล์แบตเตอรี่ถูกจัดเรียงอยู่ในป่าที่มีต้นไม้ไบนารีในอุดมคติ ต้นไม้เรียงลำดับตามความสูง การแสดงนี้ได้รับเลือกให้เป็นภาพที่มองเห็นได้มากที่สุด และช่วยให้คุณเห็นภาพการรวมตัวกันของต้นไม้ระหว่างการใช้งานแบตเตอรี่
ผู้เขียนตั้งข้อสังเกตว่าเนื่องจากต้นไม้ทุกต้นในป่าเป็นต้นไม้ในอุดมคติ ความสูงของต้นไม้จึงแสดงเป็นกำลังสอง เช่นเดียวกับที่จำนวนธรรมชาติใดๆ ก็สามารถแสดงเป็นผลรวมของกำลังสองได้ ดังนั้น ชุดใบไม้ใดๆ ก็สามารถจัดกลุ่มเป็นต้นไม้ไบนารีได้ และในทุกกรณี การเพิ่มองค์ประกอบใหม่ต้องอาศัยความรู้ เฉพาะเกี่ยวกับโหนดรากของต้นไม้ที่เก็บไว้เท่านั้น.
ดังนั้น การแสดงที่จัดเก็บไว้ของตัวสะสม Utreexo จึงเป็นรายการของโหนดรูท (รูต Merkle) และไม่ใช่ป่าไม้ทั้งหมด.
มาแสดงรายการองค์ประกอบรูทกัน Vec<Option<Hash>>
. ประเภทตัวเลือก Option<Hash>
บ่งชี้ว่าองค์ประกอบรากอาจหายไปซึ่งหมายความว่าไม่มีต้นไม้ที่มีความสูงที่เหมาะสมในตัวสะสม
/// SHA-256 хеш
#[derive(Copy, Clone, Hash, Eq, PartialEq)]
pub struct Hash(pub [u8; 32]);
#[derive(Debug, Clone)]
pub struct Utreexo {
pub roots: Vec<Option<Hash>>,
}
impl Utreexo {
pub fn new(capacity: usize) -> Self {
Utreexo {
roots: vec![None; capacity],
}
}
}
การเพิ่มองค์ประกอบ
ก่อนอื่น เรามาอธิบายฟังก์ชันกันก่อน parent()
ซึ่งจดจำโหนดพาเรนต์สำหรับองค์ประกอบที่กำหนดสองรายการ
ฟังก์ชันพาเรนต์ ()
เนื่องจากเราใช้ Merkle tree ค่าพาเรนต์ของแต่ละโหนดจึงเป็นโหนดเดียวที่เก็บแฮชของการต่อแฮชของโหนดลูก:
fn hash(bytes: &[u8]) -> Hash {
let mut sha = Sha256::new();
sha.input(bytes);
let res = sha.result();
let mut res_bytes = [0u8; 32];
res_bytes.copy_from_slice(res.as_slice());
Hash(res_bytes)
}
fn parent(left: &Hash, right: &Hash) -> Hash {
let concat = left
.0
.into_iter()
.chain(right.0.into_iter())
.map(|b| *b)
.collect::<Vec<_>>();
hash(&concat[..])
}
ผู้เขียนตั้งข้อสังเกตว่าเพื่อป้องกันการโจมตีที่อธิบายโดย Charles Bouillaguet, Pierre-Alain Fouque, Adi Shamir และ Sebastien Zimmer
เมื่อคุณเพิ่มองค์ประกอบลงในตัวสะสม คุณจะต้องติดตามว่าองค์ประกอบรากใดบ้างที่มีการเปลี่ยนแปลง การปฏิบัติตามเส้นทางของการเปลี่ยนองค์ประกอบรากสำหรับแต่ละองค์ประกอบที่คุณเพิ่ม คุณสามารถสร้างหลักฐานการมีอยู่ขององค์ประกอบเหล่านี้ได้ในภายหลัง
ติดตามการเปลี่ยนแปลงเมื่อคุณเพิ่ม
เพื่อติดตามการเปลี่ยนแปลงที่เกิดขึ้น เรามาประกาศโครงสร้างกันดีกว่า Update
ซึ่งจะเก็บข้อมูลเกี่ยวกับการเปลี่ยนแปลงโหนด
#[derive(Debug)]
pub struct Update<'a> {
pub utreexo: &'a mut Utreexo,
// ProofStep хранит "соседа" элемента и его положение
pub updated: HashMap<Hash, ProofStep>,
}
หากต้องการเพิ่มองค์ประกอบลงในแบตเตอรี่ คุณต้องมี:
- สร้างอาร์เรย์ตะกร้าองค์ประกอบราก
new_roots
และวางองค์ประกอบรากที่มีอยู่ไว้ที่นั่น หนึ่งรายการสำหรับแต่ละที่เก็บข้อมูล:
รหัส
let mut new_roots = Vec::new();
for root in self.roots.iter() {
let mut vec = Vec::<Hash>::new();
if let Some(hash) = root {
vec.push(*hash);
}
new_roots.push(vec);
}
- ผนวกองค์ประกอบที่จะเพิ่ม (array
insertions
) ไปยังรถเข็นคันแรกnew_roots[0]
:
รหัส
new_roots[0].extend_from_slice(insertions);
- รวมรายการที่เพิ่มลงในตะกร้าแรกกับส่วนที่เหลือ:
- สำหรับรถเข็นทั้งหมดที่มีมากกว่าหนึ่งรายการ:
- นำสององค์ประกอบจากส่วนท้ายของตะกร้า คำนวณองค์ประกอบหลัก ลบทั้งสององค์ประกอบ
- เพิ่มหลักจากการคำนวณไปยังรถเข็นถัดไป
- สำหรับรถเข็นทั้งหมดที่มีมากกว่าหนึ่งรายการ:
รหัส
for i in 0..new_roots.len() {
while new_roots[i].len() > 1 {
// Объединяем два элемента в один и удаляем их
let a = new_roots[i][new_roots[i].len() - 2];
let b = new_roots[i][new_roots[i].len() - 1];
new_roots[i].pop();
new_roots[i].pop();
let hash = self.parent(&a, &b);
// Наращиваем количество корзин если требуется
if new_roots.len() <= i + 1 {
new_roots.push(vec![]);
}
// Помещаем элемент в следующую корзину
new_roots[i + 1].push(hash);
// Не забываем отслеживать изменения;
// это пригодится для генерации доказательства добавления элементов
updated.insert(a, ProofStep { hash: b, is_left: false });
updated.insert(b, ProofStep {hash: a, is_left: true });
}
}
- ย้ายองค์ประกอบรูทจากถังขยะไปยังอาร์เรย์ตัวสะสมผลลัพธ์
รหัส
for (i, bucket) in new_roots.into_iter().enumerate() {
// Наращиваем аккумулятор если требуется
if self.roots.len() <= i {
self.roots.push(None);
}
if bucket.is_empty() {
self.roots[i] = None;
} else {
self.roots[i] = Some(bucket[0]);
}
}
การสร้างหลักฐานสำหรับองค์ประกอบเพิ่มเติม
หลักฐานการรวมเซลล์ไว้ในแบตเตอรี่ (Proof
) จะทำหน้าที่เป็นเส้นทาง Merkle ประกอบด้วยสายโซ่ ProofStep
. หากเส้นทางไม่นำไปสู่ที่ไหนก็แสดงว่าการพิสูจน์ไม่ถูกต้อง
/// Единичный шаг на пути к элементу в дереве Меркла.
#[derive(Debug, Copy, Clone)]
pub struct ProofStep {
pub hash: Hash,
pub is_left: bool,
}
/// Доказательство включения элемента. Содержит сам элемент и путь к нему.
#[derive(Debug, Clone)]
pub struct Proof {
pub steps: Vec<ProofStep>,
pub leaf: Hash,
}
การใช้ข้อมูลที่ได้รับก่อนหน้านี้เมื่อเพิ่มองค์ประกอบ (structural Update
) คุณสามารถสร้างหลักฐานว่ามีการเพิ่มองค์ประกอบลงในแบตเตอรี่แล้ว ในการทำเช่นนี้ เราจะดูตารางการเปลี่ยนแปลงที่เกิดขึ้นและเพิ่มแต่ละขั้นตอนในเส้นทางของ Merkle ซึ่งจะใช้เป็นข้อพิสูจน์ในภายหลัง:
รหัส
impl<'a> Update<'a> {
pub fn prove(&self, leaf: &Hash) -> Proof {
let mut proof = Proof {
steps: vec![],
leaf: *leaf,
};
let mut item = *leaf;
while let Some(s) = self.updated.get(&item) {
proof.steps.push(*s);
item = parent(&item, &s);
}
proof
}
}
กระบวนการสร้างหลักฐาน
การตรวจสอบการพิสูจน์องค์ประกอบ
การตรวจสอบหลักฐานการรวมขององค์ประกอบนั้นจะต้องดำเนินการตามเส้นทาง Merkle จนกว่าจะนำไปสู่องค์ประกอบรูทที่มีอยู่:
pub fn verify(&self, proof: &Proof) -> bool {
let n = proof.steps.len();
if n >= self.roots.len() {
return false;
}
let expected = self.roots[n];
if let Some(expected) = expected {
let mut current_parent = proof.leaf;
for s in proof.steps.iter() {
current_parent = if s.is_left {
parent(&s.hash, ¤t_parent)
} else {
parent(¤t_parent, &s.hash)
};
}
current_parent == expected
} else {
false
}
}
สายตา:
ขั้นตอนการตรวจสอบหลักฐาน ก
กำลังถอดรายการ
หากต้องการถอดเซลล์ออกจากแบตเตอรี่ คุณต้องแสดงหลักฐานที่ถูกต้องว่ามีเซลล์อยู่ที่นั่น การใช้ข้อมูลจากการพิสูจน์ ทำให้เป็นไปได้ที่จะคำนวณองค์ประกอบรากใหม่ของตัวสะสม ซึ่งการพิสูจน์ที่ให้มาจะไม่เป็นจริงอีกต่อไป
อัลกอริทึมมีดังนี้:
- นอกจากนี้เรายังจัดชุดตะกร้าเปล่าที่สอดคล้องกับต้น Merkle ที่มีความสูงเท่ากับยกกำลังสองจากดัชนีตะกร้า
- เราใส่องค์ประกอบจากขั้นบันไดของเส้นทาง Merkle ลงในตะกร้า ดัชนีตะกร้าเท่ากับจำนวนขั้นตอนปัจจุบัน
- เราลบองค์ประกอบรากที่พาธออกจากการพิสูจน์
- เช่นเดียวกับการเพิ่ม เราจะคำนวณองค์ประกอบรากใหม่โดยการรวมองค์ประกอบจากตะกร้าเป็นคู่และย้ายผลลัพธ์ของการรวมไปยังตะกร้าถัดไป
รหัส
fn delete(&self, proof: &Proof, new_roots: &mut Vec<Vec<Hash>>) -> Result<(), ()> {
if self.roots.len() < proof.steps.len() || self.roots.get(proof.steps.len()).is_none() {
return Err(());
}
let mut height = 0;
let mut hash = proof.leaf;
let mut s;
loop {
if height < new_roots.len() {
let (index, ok) = self.find_root(&hash, &new_roots[height]);
if ok {
// Remove hash from new_roots
new_roots[height].remove(index);
loop {
if height >= proof.steps.len() {
if !self.roots[height]
.and_then(|h| Some(h == hash))
.unwrap_or(false)
{
return Err(());
}
return Ok(());
}
s = proof.steps[height];
hash = self.parent(&hash, &s);
height += 1;
}
}
}
if height >= proof.steps.len() {
return Err(());
}
while height > new_roots.len() {
new_roots.push(vec![]);
}
s = proof.steps[height];
new_roots[height].push(s.hash);
hash = self.parent(&hash, &s);
height += 1;
}
}
กระบวนการลบองค์ประกอบ "A":
บูรณาการเข้ากับเครือข่ายที่มีอยู่
เมื่อใช้ตัวสะสมที่นำเสนอ โหนดสามารถหลีกเลี่ยงการใช้ฐานข้อมูลเพื่อจัดเก็บ UTXO ทั้งหมดในขณะที่ยังคงสามารถเปลี่ยนชุด UTXO ได้ อย่างไรก็ตาม ปัญหาในการทำงานกับหลักฐานก็เกิดขึ้น
ลองเรียกโหนดตรวจสอบที่ใช้ตัวสะสม UTXO กะทัดรัด (compact-state node) และผู้ตรวจสอบที่ไม่มีตัวสะสมก็คือ เต็ม (โหนดเต็ม) การมีอยู่ของโหนดสองคลาสสร้างปัญหาในการรวมโหนดเหล่านั้นไว้ในเครือข่ายเดียว เนื่องจากโหนดขนาดกะทัดรัดจำเป็นต้องมีการพิสูจน์การมีอยู่ของ UTXO ซึ่งใช้ในธุรกรรม ในขณะที่โหนดแบบเต็มไม่ต้องการ หากโหนดเครือข่ายทั้งหมดไม่พร้อมกันและสลับไปใช้ Utreexo ในลักษณะที่มีการประสานงาน โหนดขนาดเล็กจะถูกทิ้งไว้ข้างหลังและจะไม่สามารถดำเนินการบนเครือข่าย Bitcoin ได้
เพื่อแก้ปัญหาการรวมโหนดขนาดกะทัดรัดเข้ากับเครือข่ายขอแนะนำให้แนะนำคลาสโหนดเพิ่มเติม - สะพาน. โหนดบริดจ์เป็นโหนดที่สมบูรณ์ซึ่งจัดเก็บแบตเตอรี่ Utreexo และหลักฐานการเปิดเครื่องด้วย ทั้งหมด UTXO จากชุด UTXO Bridges คำนวณแฮชใหม่และอัปเดตตัวสะสมและการพิสูจน์เมื่อมีธุรกรรมบล็อกใหม่มาถึง การดูแลรักษาและการอัปเดตตัวสะสมและการพิสูจน์ไม่ได้ทำให้เกิดภาระในการคำนวณเพิ่มเติมบนโหนดดังกล่าว บริดจ์สละพื้นที่ดิสก์: จำเป็นต้องจัดระเบียบสิ่งต่างๆ แฮชเมื่อเปรียบเทียบกับ แฮชสำหรับโหนดขนาดกะทัดรัด โดยที่ n คือพลังของชุด UTXO
สถาปัตยกรรมเครือข่าย
บริดจ์ทำให้สามารถค่อยๆ เพิ่มโหนดขนาดกะทัดรัดลงในเครือข่ายได้โดยไม่ต้องเปลี่ยนซอฟต์แวร์ของโหนดที่มีอยู่ โหนดเต็มรูปแบบทำงานเหมือนเดิม โดยกระจายธุรกรรมและบล็อกระหว่างกัน โหนดบริดจ์เป็นโหนดเต็มรูปแบบที่จัดเก็บข้อมูลแบตเตอรี่ Utreexo เพิ่มเติมและชุดการพิสูจน์การรวม ทั้งหมด UTXO ในตอนนี้ โหนดบริดจ์ไม่ได้โฆษณาตัวเองเช่นนั้น โดยแสร้งทำเป็นโหนดเต็มสำหรับโหนดเต็มทั้งหมด และเป็นโหนดขนาดกะทัดรัดสำหรับโหนดที่มีขนาดกะทัดรัดทั้งหมด แม้ว่าบริดจ์จะเชื่อมต่อทั้งสองเครือข่ายเข้าด้วยกัน แต่จริงๆ แล้วจำเป็นต้องเชื่อมต่อในทิศทางเดียวเท่านั้น: จากโหนดเต็มที่มีอยู่ไปจนถึงโหนดขนาดกะทัดรัด สิ่งนี้เป็นไปได้เนื่องจากไม่จำเป็นต้องเปลี่ยนรูปแบบธุรกรรม และสามารถละทิ้งการพิสูจน์ UTXO สำหรับโหนดแบบกะทัดรัดได้ ดังนั้นโหนดแบบกะทัดรัดใดๆ ก็สามารถออกอากาศธุรกรรมในทำนองเดียวกันไปยังผู้เข้าร่วมเครือข่ายทั้งหมดโดยไม่ต้องมีส่วนร่วมของโหนดบริดจ์
ข้อสรุป
เราดูที่แบตเตอรี่ Utreexo และนำต้นแบบไปใช้ใน Rust เราพิจารณาสถาปัตยกรรมเครือข่ายที่จะช่วยให้สามารถรวมโหนดที่ใช้แบตเตอรี่ได้ ข้อดีของการกระชับข้อมูลคือขนาดของข้อมูลที่จัดเก็บ ซึ่งขึ้นอยู่กับกำลังของชุด UTXO ในลอการิทึม ซึ่งช่วยลดความต้องการพื้นที่ดิสก์และประสิทธิภาพการจัดเก็บข้อมูลสำหรับโหนดดังกล่าวได้อย่างมาก ข้อเสียคือปริมาณการรับส่งข้อมูลโหนดเพิ่มเติมสำหรับการส่งหลักฐาน แต่เทคนิคการรวมหลักฐาน (เมื่อหลักฐานหนึ่งพิสูจน์ว่ามีองค์ประกอบหลายอย่าง) และการแคชสามารถช่วยรักษาการรับส่งข้อมูลให้อยู่ในขอบเขตที่ยอมรับได้
การอ้างอิง:
GitHub ของต้นแบบ Utreexo ใน Rust แธดเดียส ดรายจา -Utreexo: ตัวสะสมตามแฮชแบบไดนามิกที่ปรับให้เหมาะกับชุด Bitcoin UTXO ภาพประกอบภาพเคลื่อนไหวจากบทความ
ที่มา: will.com