Utreexo: 倚くの UTXO ビットコむンを圧瞮

Utreexo: 倚くの UTXO ビットコむンを圧瞮

おい、ハブル

ビットコむンネットワヌクでは、すべおのノヌドがコンセンサスを通じお䞀連のUTXO、぀たり、䜕枚のコむンを、正確に誰に、どのような条件で䜿甚できるかに぀いお合意したす。 UTXO セットはバリデヌタヌ ノヌドに必芁な最小限のデヌタ セットであり、これがないずノヌドは受信トランザクションずそれらを含むブロックの有効性を怜蚌できたせん。

この点に関しお、セキュリティの保蚌を倱わずに、このセットの保存された衚珟を削枛し、圧瞮するためのあらゆる可胜な方法が詊みられおいたす。 保存されるデヌタの量が少ないほど、怜蚌ノヌドのディスク容量芁件が少なくなり、怜蚌ノヌドの起動が安䟡になり、ネットワヌクを拡匵できるため、ネットワヌクの安定性が向䞊したす。

この投皿では、共著者からの最近の提案の Rust プロトタむプを投皿したす。 ラむトニングネットワヌク甚玙, タデりス・ドラむダ - Utreexo: ビットコむン UTXO セット甚に最適化された動的ハッシュベヌスのアキュムレヌタヌこれにより、バリデヌタヌ ノヌドのディスク容量芁件を削枛できたす。

問題は䜕ですか

ビットコむンの長幎の問題の XNUMX ぀は、そのスケヌラビリティです。 「自分の銀行」ずいう考えでは、ネットワヌク参加者は䜿甚可胜なすべおの資金の蚘録を保持する必芁がありたす。 ビットコむンでは、利甚可胜な資金は未䜿甚の出力のセット、぀たり UTXO セットずしお衚珟されたす。 これは特に盎芳的な衚珟ではありたせんが、各「りォレット」が別個の゚ントリずしお「残高」を持぀衚珟よりも実装パフォヌマンスの点で有益であり、プラむバシヌも远加されたす䟋: コむンゞョむン).

トランザクションの履歎 (いわゆるブロックチェヌン) ずシステムの珟圚の状態を区別するこずが重芁です。 ビットコむンのトランザクション履歎は珟圚、玄 200 GB のディスク容量を占めおおり、増加し続けおいたす。 ただし、システム状態は 4 GB 皋床ずはるかに小さく、誰かが珟圚コむンを所有しおいるずいう事実のみが考慮されたす。 このデヌタの量も時間の経過ずずもに増加したすが、その速床ははるかに遅く、堎合によっおは枛少する傟向さえありたす (CDPV を参照)。

ラむト クラむアント (SPV) は、セキュリティの保蚌ず匕き換えに、秘密キヌ以倖の最小状態 (UTXO セット) を保存できない機胜を備えおいたす。

UTXO および UTXO セット

UTXO (Unspent Transaction Output) は、未䜿甚のトランザクション出力であり、トランザクションで転送された各サトシの旅の終点です。 䜿甚されなかった出力は新しいトランザクションの入力ずなるため、䜿甚され (spend)、UTXO セットから削陀されたす。

新しい UTXO は垞にトランザクションによっお䜜成されたす。

  • 入力のない Coinbase トランザクション: マむナヌがコむンを発行するずきに新しい UTXO を䜜成したす
  • 通垞のトランザクション: 既存の UTXO の特定のセットを䜿甚しながら、新しい UTXO を䜜成したす。

UTXO を䜿甚するプロセス:
Utreexo: 倚くの UTXO ビットコむンを圧瞮

りォレットは、このりォレットで䜿甚可胜な UTXO の量に基づいお、䜿甚可胜なコむンの数 (残高) をカりントしたす。

各バリデヌタヌ ノヌドは、二重支出の詊行を防ぐために、セットを監芖する必芁がありたす。 すべお UTXO確認時 各 トランザクション それぞれの ブロック。

ノヌドには次のロゞックが必芁です。

  • UTXO セットぞの远加
  • UTXO セットからの削陀
  • セット内の単䞀の UTXO の存圚を確認する

芁玠の远加ず削陀、セット内の芁玠の存圚の確認ず蚌明を行う機胜を維持しながら、セットに関する保存情報の芁件を軜枛する方法がありたす。 暗号アキュムレヌタ.

UTXO甚バッテリヌ

バッテリヌを䜿甚しお耇数のUTXOを保管するずいうアむデア 話し合った 前.

UTXO セットは、初期ブロック ダりンロヌド (IBD) 䞭にオンザフラむで構築され、完党か぀氞続的に保存されたすが、その内容は、ネットワヌクの新しい正しいブロックごずにトランザクションを凊理した埌に倉曎されたす。 このプロセスでは、玄 200 GB のブロック デヌタをダりンロヌドし、数億のデゞタル眲名を怜蚌する必芁がありたす。 IBD プロセスが完了するず、UTXO セットは玄 4 GB を占有するこずになりたす。

しかし、アキュムレヌタヌを䜿甚するず、資金の合意ルヌルは怜蚌ず暗号蚌明の生成に簡玠化され、利甚可胜な資金を远跡する負担は、資金の存圚ず所有暩の蚌明を提䟛する資金の所有者に移されたす。

アキュムレヌタは、セットのコンパクトな衚珟ず呌ぶこずができたす。 保存された衚珟のサむズは定数である必芁がありたす。 Utreexo: 倚くの UTXO ビットコむンを圧瞮たたは、セットのカヌディナリティず芁玠自䜓のサむズに関しお線圢的に増加したせん。たずえば、 Utreexo: 倚くの UTXO ビットコむンを圧瞮ここで、n は栌玍されたセットのカヌディナリティです。

この堎合、アキュムレヌタは、芁玠がセットに含たれおいるこずの蚌明 (包含蚌明) を生成でき、この蚌明を効果的に怜蚌できるようにする必芁がありたす。

バッテリヌず呌ばれたす ダむナミック if を䜿甚するず、セットに芁玠を远加したり、セットから芁玠を削陀したりできたす。

そのようなバッテリヌの䟋は次のずおりです。 2018 幎 XNUMX 月に Boneh、Bunz、Fisch によっお提案された RSA アキュムレヌタ。 このようなアキュムレヌタは、栌玍された衚珟のサむズが䞀定ですが、存圚する必芁がありたす。 共有秘密 (信頌できるセットアップ)。 この芁件は、ビットコむンのようなトラストレス ネットワヌクに察するこのようなアキュムレヌタの適甚性を無効にしたす。シヌクレット生成䞭のデヌタ挏掩により、攻撃者が UTXO の存圚の停りの蚌拠を䜜成し、そのようなアキュムレヌタに基づく UTXO セットでノヌドを欺く可胜性があるためです。

りトレク゜

Thaddeus Dryja によっお提案された Utreexo デザむンにより、 ダむナミック アキュムレヌタ без 信頌できるセットアップ。

Utreexo は完璧なバむナリの森です マヌクルの朚 で提瀺されたアむデアを発展させたものです。 分散型 pki 甚の効率的な非同期アキュムレヌタ、セットから芁玠を削陀する機胜が远加されたした。

バッテリヌの論理構造

バッテリヌセルは、理想的な二分朚の森の䞭に配眮されおいたす。 朚は高さ順に䞊べられたす。 この衚珟は最も芖芚的に遞択されおおり、バッテリヌでの操䜜䞭にツリヌの結合を芖芚化できたす。

著者は、森の䞭の朚はすべお理想的なので、自然数が XNUMX の环乗の和で衚珟できるのず同様に、その高さも XNUMX の环乗で衚珟されるず述べおいたす。 したがっお、任意のリヌフのセットをバむナリ ツリヌにグルヌプ化できたす。どの堎合でも、新しい芁玠を远加するには知識が必芁です。 保存されたツリヌのルヌト ノヌドのみに぀いお.

したがっお、Utreexo アキュムレヌタの保存衚珟はルヌト ノヌド (マヌクル ルヌト) のリストです。 朚の森党䜓ではありたせん.

ルヌト芁玠のリストを次のように衚したす。 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()、指定された XNUMX ぀の芁玠の芪ノヌドを認識したす。

芪()関数

マヌクル ツリヌを䜿甚しおいるため、XNUMX ぀のノヌドのそれぞれの芪は、子ノヌドのハッシュを連結したハッシュを栌玍する XNUMX ぀のノヌドになりたす。

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[..])
}

著者は、シャルル・ブむダゲ、ピ゚ヌルアラン・フヌク、アディ・シャミヌル、セバスチャン・ゞマヌが述べた攻撃を防ぐには次のように述べおいる。
ディザリングされたハッシュ関数に察する XNUMX 回目のプリむメヌゞ攻撃、XNUMX ぀のハッシュに加えお、ツリヌ内の高さも連結に远加する必芁がありたす。

アキュムレヌタに芁玠を远加するずきは、どのルヌト芁玠が倉曎されたかを远跡する必芁がありたす。 远加する各芁玠のルヌト芁玠を倉曎するパスに埓うこずで、埌でこれらの芁玠の存圚の蚌明を構築できたす。

远加時に倉曎を远跡する

加えられた倉曎を远跡するには、構造䜓を宣蚀したしょう Update、ノヌドの倉曎に関するデヌタが保存されたす。

#[derive(Debug)]
pub struct Update<'a> {
    pub utreexo: &'a mut Utreexo,
    // ProofStep храМОт "сПсеЎа" элеЌеМта О егП пПлПжеМОе
    pub updated: HashMap<Hash, ProofStep>,
}

バッテリヌに芁玠を远加するには、以䞋が必芁です。

  • ルヌト芁玠のバスケットの配列を䜜成する new_roots そしお、既存のルヌト芁玠をバケットごずに XNUMX ぀ず぀そこに配眮したす。

コヌド

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);
}

  • 远加する芁玠(配列)を远加したす。 insertions) 最初のカヌトぞ new_roots[0]:

Utreexo: 倚くの UTXO ビットコむンを圧瞮

コヌド

new_roots[0].extend_from_slice(insertions);

  • 最初のバスケットに远加したアむテムを残りのアむテムず結合したす。
    • 耇数の商品が入っおいるすべおのカヌトの堎合:
      1. バスケットの端から XNUMX ぀の芁玠を取り出し、それらの芪を蚈算し、䞡方の芁玠を削陀したす
      2. 蚈算された芪を次のカヌトに远加したす

Utreexo: 倚くの UTXO ビットコむンを圧瞮

コヌド

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) はチェヌンで構成されるマヌクル パスずしお機胜したす。 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,
}

芁玠構造䜓を远加するずきに、以前に取埗した情報を䜿甚したす。 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
    }
}

プルヌフ䜜成の流れ

Utreexo: 倚くの UTXO ビットコむンを圧瞮

芁玠の蚌明をチェックする

芁玠の包含蚌明のチェックは、既存のルヌト芁玠に至るたでマヌクル パスをたどるこずに芁玄されたす。

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, &current_parent)
            } else {
                parent(&current_parent, &s.hash)
            };
        }

        current_parent == expected
    } else {
        false
    }
}

明らかに

Aの蚌明をチェックするプロセス

Utreexo: 倚くの UTXO ビットコむンを圧瞮

アむテムの削陀

バッテリヌからセルを取り倖すには、そのセルがそこにあるずいう有効な蚌拠を提䟛する必芁がありたす。 蚌明からのデヌタを䜿甚するず、指定された蚌明が真ではなくなるアキュムレヌタの新しいルヌト芁玠を蚈算するこずができたす。

アルゎリズムは次のずおりです。

  1. 远加ず同様に、バスケット むンデックスから XNUMX の环乗に等しい高さのマヌクル ツリヌに察応する空のバスケットのセットを線成したす。
  2. マヌクル パスのステップからの芁玠をバスケットに挿入したす。 バスケットむンデックスは珟圚のステップの番号に等しい
  3. 蚌明からのパスが導くルヌト芁玠を削陀したす
  4. 加算ず同様に、バスケットの芁玠をペアで結合し、結合の結果を次のバスケットに移動するこずによっお、新しいルヌト芁玠を蚈算したす。

コヌド

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」を削陀するプロセス:
Utreexo: 倚くの UTXO ビットコむンを圧瞮

既存のネットワヌクぞの統合

提案されたアキュムレヌタを䜿甚するず、ノヌドは、UTXO セットを倉曎できる䞀方で、すべおの UTXO を栌玍するために DB を䜿甚するこずを回避できたす。 ただし、蚌拠の扱いに問題が生じたす。

UTXO アキュムレヌタを䜿甚するバリデヌタ ノヌドを呌び出しおみたしょう コンパクト (コンパクト状態ノヌド)、アキュムレヌタのないバリデヌタは次のようになりたす。 完成する (フルノヌド)。 XNUMX ぀のクラスのノヌドが存圚するず、それらを単䞀のネットワヌクに統合する際に問題が生じたす。これは、コンパクト ノヌドではトランザクションで消費される UTXO の存圚蚌明が必芁ですが、フル ノヌドでは必芁がないためです。 すべおのネットワヌク ノヌドが同時に連携しお Utreexo の䜿甚に切り替えないず、コンパクト ノヌドが取り残され、ビットコむン ネットワヌクで動䜜できなくなりたす。

コンパクトなノヌドをネットワヌクに統合するずいう問題を解決するために、远加のノヌド クラスを導入するこずが提案されおいたす。 橋。 ブリッゞ ノヌドは、Utreexo バッテリヌず電源投入蚌明も保存する完党なノヌドです。 すべお UTXOセットのUTXO。 ブリッゞは、トランザクションの新しいブロックが到着するず、新しいハッシュを蚈算し、アキュムレヌタず蚌明を曎新したす。 アキュムレヌタず蚌明を維持および曎新しおも、そのようなノヌドに远加の蚈算負荷がかかるこずはありたせん。 ブリッゞはディスク容量を犠牲にしたす: 物事を敎理しおおく必芁がありたす Utreexo: 倚くの UTXO ビットコむンを圧瞮 ハッシュず比范しお Utreexo: 倚くの UTXO ビットコむンを圧瞮 コンパクト ノヌドのハッシュ。n は UTXO セットの环乗です。

ネットワヌク アヌキテクチャ

Utreexo: 倚くの UTXO ビットコむンを圧瞮

ブリッゞを䜿甚するず、既存のノヌドの゜フトりェアを倉曎するこずなく、コンパクトなノヌドをネットワヌクに埐々に远加するこずができたす。 フルノヌドは以前ず同様に動䜜し、トランザクションずブロックをノヌド間で分散したす。 ブリッゞ ノヌドは、Utreexo バッテリヌ デヌタず䞀連の包含蚌明を远加で保存する完党なノヌドです。 すべお ずりあえずUTXO。 ブリッゞ ノヌドは、それ自䜓をそのようにアドバタむズせず、すべおのフル ノヌドに察しおはフル ノヌド、すべおのコンパクト ノヌドに察しおはコンパクト ノヌドであるふりをしたす。 ブリッゞは䞡方のネットワヌクを接続したすが、実際には、既存のフル ノヌドからコンパクト ノヌドぞずいう䞀方向にのみ接続する必芁がありたす。 これが可胜なのは、トランザクション圢匏を倉曎する必芁がなく、コンパクト ノヌドの UTXO プルヌフを砎棄できるためです。そのため、ブリッゞ ノヌドの参加なしに、どのコンパクト ノヌドも同様にすべおのネットワヌク参加者にトランザクションをブロヌドキャストできたす。

たずめ

私たちは Utreexo バッテリヌを調べ、そのプロトタむプを Rust に実装したした。 私たちは、バッテリヌベヌスのノヌドの統合を可胜にするネットワヌク アヌキテクチャを怜蚎したした。 コンパクト キャッチの利点は、保存されるデヌタのサむズが UTXO のセットの胜力に察数的に䟝存するこずです。これにより、そのようなノヌドのディスク領域ずストレヌゞ パフォヌマンスの芁件が倧幅に軜枛されたす。 欠点は、プルヌフを送信するための远加のノヌド トラフィックですが、蚌拠集玄技術 (XNUMX ぀のプルヌフが耇数の芁玠の存圚を蚌明する堎合) ずキャッシュにより、トラフィックを蚱容範囲内に抑えるこずができたす。

リファレンス:

出所 habr.com

コメントを远加したす