follow the Satoshi算法

follow the Satoshi

follow-the-satoshi算法是李啟威在2012年發(fā)明的,算法的原理非常簡單:將所有的權(quán)益組成一棵Merkletree,其形式是非葉子節(jié)點的權(quán)重為左右子樹的權(quán)重之和,葉子節(jié)點的權(quán)重即為某個權(quán)益所有者的權(quán)益值。然后根據(jù)隨機(jī)數(shù)在左右子樹中進(jìn)行選擇。


例如上圖選擇:

  • 隨機(jī)數(shù)是65,左邊權(quán)益是50度迂,那么65>50所以選擇右邊
  • 執(zhí)行偽隨機(jī)得到20,左邊權(quán)益37猜揪,20<37惭墓,選擇左邊
  • 執(zhí)行偽隨機(jī)得到15,左邊權(quán)益27而姐,15<27腊凶,選擇左邊,所以最終選擇出A4作為這一輪的stakeholder拴念。

構(gòu)建

通過質(zhì)押或其他方式產(chǎn)生一組滿足一定條件(達(dá)到一定質(zhì)押比例)的Stakeholder作為葉子節(jié)點钧萍,其質(zhì)押量作為其權(quán)重,用于構(gòu)建一個Merkle樹政鼠。风瘦,將Stakeholder作為葉子節(jié)點,其質(zhì)押量作為其權(quán)重公般,用于構(gòu)建一個Merkle樹万搔。

pub fn create_merkle_tree(stakeholders: Vec<Stakeholder>) -> Vec<Arc<Node>> {
    let mut tree: Vec<Arc<Node>> = Vec::new();
    tree.resize(stakeholders.len() * 2,Arc::new(Node::default()));
    println!("Creating Merkle tree with:{} nodes",tree.len() - 1);
    for i in 0..stakeholders.len() {
        if let Some(v) = tree.get_mut(i+stakeholders.len()) {
            *v = Arc::new(Node::new_node_from_SHolder(stakeholders.get(i).unwrap().clone()));
        }
    }
    for i in (1..stakeholders.len()).rev() {
        let mut left: Arc<Node>;
        let mut right: Arc<Node>;
        let mut h: Hash;
        {
            left = tree.get(i*2).unwrap().clone();
            right = tree.get(i*2 + 1).unwrap().clone();
            h = makeNodeHash(left.getMerkleHash().to_slice(),
                                right.getMerkleHash().to_slice(),
                                &left.getCoins().to_string().into_bytes(),
                                &right.getCoins().to_string().into_bytes());
        }
        if let Some(v) = tree.get_mut(i) {
            *v = Arc::new(Node::new_node(Some(left), Some(right), h));
        }
    }
    for i in (1..tree.len()) {
        println!("HASH:{:?},Index:{}",tree.get(i).unwrap().getMerkleHash(),i);
    }
    return tree;
}

隨機(jī)選擇

從該Merkletree的根節(jié)點開始胡桨,以一個隨機(jī)種子,使用偽隨機(jī)數(shù)生成器生成一個小于當(dāng)前樹節(jié)點權(quán)重的隨機(jī)數(shù)瞬雹,如果該隨機(jī)數(shù)小于左子樹的權(quán)重則選擇左子樹繼續(xù)遍歷昧谊,否則選擇右子樹繼續(xù)遍歷,直到選擇某一個葉子節(jié)點酗捌,也即選擇了該葉子節(jié)點所代表的權(quán)益所有者作為下一個出塊的Leader呢诬。

pub fn random_from_fts_Tree(tree: Vec<Arc<Node>>,rnd: &mut StdRng) -> Box<ftsResult> {
    let mut merkleProof: Vec<ProofEntry> = Vec::new();
    let mut i: usize = 1;
    loop {
        if tree[i].isLeaf() {
            let s = tree[i].getStakeholder();
            return Box::new(ftsResult::new_fts_result(s.as_ref().unwrap(),merkleProof));
        }
        let x1 = tree.get(i).unwrap()
                    .getLeftNode()
                    .as_ref()
                    .unwrap()
                    .getCoins();
        let x2 = tree.get(i).unwrap()
                    .getRightNode()
                    .as_ref()
                    .unwrap()
                    .getCoins();
        println!("left subtree coins:{} right subtree coins:{}",x1,x2);
        let r = nextInt(x1 + x2,rnd) + 1;
        println!("Picking coin number:{}",r);
        if r <= x1 {
            println!("Choosing left subtree...");
            i *= 2;
            merkleProof.push(ProofEntry::new_proof_entry(
                tree.get(i+1).unwrap().getMerkleHash(), 
                x1, x2));
        } else {
            println!("Choosing right subtree...");
            i = 2*i + 1;
            merkleProof.push(ProofEntry::new_proof_entry(
                tree.get(i-1).unwrap().getMerkleHash(), 
                x1, x2));
        }
    }
}

驗證

由于使用的是偽隨機(jī)數(shù)生成器,因此當(dāng)不同生成器使用同一個隨機(jī)種子來生成隨機(jī)數(shù)序列時胖缤,該隨機(jī)數(shù)序列是相同的馅巷。因此驗證的過程與選擇的過程類似,從該Merkletree的根節(jié)點開始草姻,以前面生成的隨機(jī)數(shù)作為隨機(jī)源生成隨機(jī)數(shù)進(jìn)行節(jié)點選擇,然后比較選中的樹節(jié)點的哈希值稍刀,相等則驗證通過撩独。

pub fn verify_fts(merkleRootHash: Hash, res: Box<ftsResult>,rnd: &mut StdRng) -> bool {
    let mut resPath: Vec<u8> = Vec::new(); 
    for v in res.getMerkleProof().iter() {
        let x1 = v.getLeftBound();
        let x2 = v.getRightBound();
        let r = nextInt(x1 + x2,rnd) + 1;
        if r <= x1 {
            println!("0");
            resPath.push(0);
        } else {
            println!("1");
            resPath.push(1);
        }
    }
    println!("OK");
    let ss = res.getStakeholder();
    let mut hx = make_hash(&ss.as_ref().unwrap().toBytes());
    for i in (0..res.getMerkleProof().len()).rev() {
        let proof = res.getMerkleProof().get(i).unwrap();
        let x1 = proof.getLeftBound().to_string().into_bytes();
        let x2 = proof.getRightBound().to_string().into_bytes();
        let hy = proof.getMerkleHash();
        if resPath[i] == 0_u8 {
            hx = makeNodeHash(hx.to_slice(),hy.to_slice(),&x1,&x2)
        } else {
            hx = makeNodeHash(hy.to_slice(),hx.to_slice(),&x1,&x2)
        }
        println!("Next hash:{}",hx);
    }
    if Ordering::Equal == merkleRootHash.to_vec().cmp(&hx.clone().to_vec()) {
        println!("Root hash matches!");
        return true
    } else {
        println!("Invalid Merkle proof");
        return true
    }
}

follow the Satoshi算法被用在Cardano的第一個版本中,時間被分為 slot账月,每個 slot 時長為20秒综膀。每個slot只能產(chǎn)生一個塊,若這個塊有問題局齿,或者應(yīng)該產(chǎn)出這個塊的“礦工”(也就是stakeholder的候選人)不在線剧劝,或者產(chǎn)出的塊沒有廣播給大多數(shù)人抓歼,那么這個slot是當(dāng)作廢棄的讥此,也就是會跳過這個slot的塊谣妻。多個slot為一個 epoch,權(quán)益的計算是以每個epoch開始前的歷史來計算,也就是說在這個epoch中所產(chǎn)生的權(quán)益變化不影響當(dāng)前的這個epoch中的slot的出塊者的選擇和其他和歷史相關(guān)的東西。當(dāng)前epoch中所產(chǎn)生的這些歷史只能在以后的epoch中生效辈灼。

參考:

https://github.com/iceming123/fts

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末棵介,一起剝皮案震驚了整個濱河市吧史,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌揣云,老刑警劉巖焚刚,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件碳柱,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進(jìn)店門娱节,熙熙樓的掌柜王于貴愁眉苦臉地迎上來掰担,“玉大人,你說我怎么就攤上這事灯蝴∫蚋荆” “怎么了狡忙?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵拓颓,是天一觀的道長。 經(jīng)常有香客問我酬核,道長,這世上最難降的妖魔是什么适室? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任嫡意,我火速辦了婚禮,結(jié)果婚禮上捣辆,老公的妹妹穿的比我還像新娘蔬螟。我一直安慰自己,他們只是感情好汽畴,可當(dāng)我...
    茶點故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布旧巾。 她就那樣靜靜地躺著,像睡著了一般忍些。 火紅的嫁衣襯著肌膚如雪鲁猩。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天罢坝,我揣著相機(jī)與錄音廓握,去河邊找鬼。 笑死嘁酿,一個胖子當(dāng)著我的面吹牛隙券,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播闹司,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼娱仔,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了游桩?” 一聲冷哼從身側(cè)響起牲迫,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎借卧,沒想到半個月后恩溅,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡谓娃,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年脚乡,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,577評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡奶稠,死狀恐怖俯艰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情锌订,我是刑警寧澤竹握,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站辆飘,受9級特大地震影響啦辐,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蜈项,卻給世界環(huán)境...
    茶點故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一芹关、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧紧卒,春花似錦侥衬、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至博个,卻和暖如春怀樟,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背盆佣。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工往堡, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人罪塔。 一個月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像养葵,于是被迫代替她去往敵國和親征堪。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,452評論 2 348