成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

node.js與比特幣

2json / 1042人閱讀

摘要:交易我們都知道得到比特幣需要挖礦,其實挖礦也屬于一種交易,不過是一種沒有確定交易輸入的一種交易,它也被稱作交易。這筆交易由轉(zhuǎn)賬發(fā)發(fā)起,因此需要提供轉(zhuǎn)賬方的私鑰進(jìn)行解鎖腳本。驗證通過則證明這是屬于轉(zhuǎn)賬方的,可以用于交易。

BTC中的utxo模型

BTC中引入了許多創(chuàng)新的概念與技術(shù),區(qū)塊鏈、PoW共識、RSA加密、萌芽階段的智能合約等名詞是經(jīng)常被圈內(nèi)人所提及,誠然這些創(chuàng)新的實現(xiàn)使得BTC變成了一種有可靠性和安全性保證的封閉生態(tài)系統(tǒng),但是在這個BTC生態(tài)中如果沒有搭配區(qū)塊鏈模式的轉(zhuǎn)賬模塊,那么貨幣的流通屬性也就無從談起了。若要實現(xiàn)轉(zhuǎn)賬交易模塊, “是否采用傳統(tǒng)的賬戶模型實現(xiàn)交易;如何在區(qū)塊鏈上存儲交易信息,如何實現(xiàn)信息壓縮;如何驗證交易信息;系統(tǒng)的最大交易并發(fā)量”等問題確實值得思考。

BTC一一解決了這些,它放棄了傳統(tǒng)的基于賬戶的交易模型,而是采用基于區(qū)塊鏈存儲的utxo(unspent transaction output)模型。筆者嘗試分析了為什么不使用傳統(tǒng)的賬戶模型:

BTC的存儲單元為區(qū)塊鏈,區(qū)塊鏈的數(shù)據(jù)結(jié)構(gòu)本質(zhì)上是單向鏈表,它并不是傳統(tǒng)的關(guān)系型數(shù)據(jù)庫,無法新建賬戶表

存儲壓力。如果采用傳統(tǒng)的方式,則賬戶表會隨著時間的推移不停地增大,為后續(xù)的表的分片與備份造成很大困難

易造成隱私泄露。賬戶表的信息會直觀的暴露余額等敏感信息

utxo模型則很有技巧的避免了這些,在utxo模型下實現(xiàn)的每一筆交易,都不需要顯式的提供轉(zhuǎn)賬地址和接收地址(utxo中沒有賬戶,也不需要提供地址),只需提供這比交易的 交易輸入交易輸出 即可,而交易輸入與交易輸出又是什么?

交易輸入指向一筆交易輸出,而且 “這筆交易輸出是可以供轉(zhuǎn)賬者消費的,因此這筆交易輸出也被稱作utxo(未花費交易輸出)”,它包括“某一筆交易、指向這筆交易的某個可用交易輸出的索引值和一個解鎖腳本”。這個解鎖腳本用來驗證某筆可用的消費輸出是否可以被提供解鎖腳本的人所使用。

交易輸出則是存儲BTC“余額”的一個數(shù)據(jù)結(jié)構(gòu),它廣義上包括兩部分:BTC的數(shù)量和一個鎖定腳本。 BTC的數(shù)量可以理解為余額,表示這筆交易產(chǎn)生的結(jié)果;而鎖定腳本則是用某種算法鎖定這個BTC余額,直到某人可以提供解鎖該腳本的數(shù)據(jù)鑰匙,這比數(shù)額BTC才會被這個人所消費。

從這個角度看,一筆交易會包含若干個交易輸入,同時產(chǎn)生若干個交易輸出。這些交易輸入都會指向之前某筆交易的未被消費輸出(utxo),并提供各自的解鎖腳本以證明這些utxo里的BTC是屬于轉(zhuǎn)賬方;同時將轉(zhuǎn)賬產(chǎn)生的所有交易輸出用對應(yīng)方的公鑰進(jìn)行加密(此處是為了更好的理解才解釋為公鑰加密,實質(zhì)上是公鑰哈希,即btc地址進(jìn)行逆向base58編碼的一段字符串),鎖定這幾筆交易輸出,等待交易輸入中的解鎖腳本解鎖。

所以,BTC沒有賬戶的概念,所有的“余額”都在區(qū)塊鏈上,不過這些余額都已經(jīng)被加密了,只有提供私鑰和簽名的人才可以使用對應(yīng)的utxo的余額,因此這就是為什么BTC持有者必須保存好自己的私鑰的原因。

UTXO的node.js實現(xiàn) 交易輸入
export class Input {
    private txId: string;
    private outputIndex: number;
    private unlockScript: string;

    public get $txId(): string {
        return this.txId;
    }

    public set $txId(value: string) {
        this.txId = value;
    }
    
    public get $outputIndex(): number {
        return this.outputIndex;
    }

    public set $outputIndex(value: number) {
        this.outputIndex = value;
    }

    public get $unlockScript(): string {
        return this.unlockScript;
    }

    public set $unlockScript(value: string) {
        this.unlockScript = value;
    }
    
    constructor(txId: string, index: number, unlockScript: string){
        this.txId = txId;
        this.outputIndex = index;
        this.unlockScript = unlockScript;
    }

    // 反序列化,進(jìn)行類型轉(zhuǎn)換
    public static createInputsFromUnserialize(objs: Array){
        let ins = [];
        objs.forEach((obj)=>{
            ins.push(new Input(obj.txId,obj.outputIndex,obj.unlockScript));
        });
        return ins;
    }
    
    canUnlock (privateKey: string): boolean{
        if(privateKey == this.unlockScript){
            return true;
        }else{
            return false;
        }
    }
}

私有屬性txId標(biāo)識 “某個可用的utxo所屬的交易”,是一串sha256編碼的字符串;
outputIndex表示 “這個可用的utxo在對應(yīng)交易的序號值”;
unlockScript則是解鎖腳本,此處并未完全按照BTC的原型去實現(xiàn),而是簡單的驗證使用者的私鑰來實現(xiàn)鑒權(quán),原理上仍遵從BTC的思想。

交易輸出
import * as rsaConfig from "../../rsa.json";
export class Output {
    private value: number;
    // 鎖定腳本,需要使用UTXO歸屬者用私鑰進(jìn)行簽名通過
    // 當(dāng)解鎖UTXO成功后,此UTXO變?yōu)橄乱粋€交易的交易輸入,同時使用接收方的地址(公鑰)鎖定本次交易的交易輸出,
    // 等待接收方使用私鑰簽名使用該UTXO
    // 因此,btc沒有賬戶的概念,所有的“錢”由自己的公鑰所加密保存,只有用自己的私鑰才能使用這些錢(即解鎖了UTXO的解鎖腳本)
    private lockScript: string;

    // 該屬性僅僅在交易時使用,設(shè)置屬性
    private txId: string;

    // 該屬性僅僅在交易時使用,設(shè)置屬性
    private index: number;

    public get $index(): number {
        return this.index;
    }

    public set $index(value: number) {
        this.index = value;
    }
    
    public get $txId(): string {
        return this.txId;
    }

    public set $txId(value: string) {
        this.txId = value;
    }
    

    public get $value(): number {
        return this.value;
    }

    public set $value(value: number) {
        this.value = value;
    }

    /* public get $lockScript(): string {
        return this.lockScript;
    }

    public set $lockScript(value: string) {
        this.lockScript = value;
    } */
    
    constructor(value: number,publicKey: string){
        this.value = value;
        this.lockScript = publicKey;
    }

    // 反序列化,進(jìn)行類型轉(zhuǎn)換
    public static createOnputsFromUnserialize(objs: Array){
        let outs = [];
        objs.forEach((obj)=>{
            outs.push(new Output(obj.value,obj.lockScript));
        });
        return outs;
    }

    public canUnlock(privateKey: string): boolean{
        if(privateKey == rsaConfig[this.lockScript]){
            return true;
        }else{
            return false;
        }
    }
}

交易輸出中的value屬性標(biāo)識當(dāng)前utxo的余額,即BTC個數(shù);
lockScript屬性為鎖定腳本,在我們的簡易實現(xiàn)中就為接收方的公鑰,并不是BTC中的逆波蘭式,但大體原理相同,都需要提供私鑰來進(jìn)行解密。

一筆交易

一筆交易,包含了若干個交易輸入和交易輸出,同時也提供了一個txId唯一的標(biāo)識這比交易。從結(jié)構(gòu)上看是這樣的:

export class Transaction {
    private txId: string;
    private inputTxs: Array;
    private outputTxs: Array;

    constructor(txId: string, inputs: Array, outputs: Array){
        this.txId = txId;
        this.inputTxs = inputs;
        this.outputTxs = outputs;
    }

    public get $txId(): string {
        return this.txId;
    }

    public set $txId(value: string) {
        this.txId = value;
    }

    public get $inputTxs(): Array {
        return this.inputTxs;
    }

    public set $inputTxs(value: Array) {
        this.inputTxs = value;
    }

    public get $outputTxs(): Array {
        return this.outputTxs;
    }

    public set $outputTxs(value: Array) {
        this.outputTxs = value;
    }
    /* 
        1.交易結(jié)構(gòu)各字段序列化為字節(jié)數(shù)組
        2.把字節(jié)數(shù)組拼接為支付串
        3.對支付串計算兩次SHA256 得到交易hash 
    */
    public setTxId(){
        let sha256 = crypto.createHash("sha256");
        sha256.update(JSON.stringify(this.inputTxs) + JSON.stringify(this.outputTxs) + Date.now(),"utf8");
        this.txId = sha256.digest("hex");
    }

}

其中 txId的計算這里并沒有嚴(yán)格按照BTC實現(xiàn)的那樣進(jìn)行計算,而是簡單的進(jìn)行對象序列化進(jìn)行一次sha256。

coinbase交易

我們都知道得到比特幣需要挖礦,其實挖礦也屬于一種交易,不過是一種沒有確定交易輸入的一種交易,它也被稱作coinbase交易。coinbase交易在每一個區(qū)塊中都會存在,它的總額包括了系統(tǒng)針對礦工打包交易過程的獎勵以及其他轉(zhuǎn)賬方提供的手續(xù)費,如下圖:

因此,創(chuàng)建一個coinbase交易也很容易

    // coinbase交易用于給礦工獎勵,input為空,output為礦工報酬
    public static createCoinbaseTx(pubKey: string, info: string){
        let input = new Input("",-1,info);
        let output = new Output(AWARD, pubKey);
        let tx = new Transaction("",[input],[output])
        tx.setTxId();
        return tx;
    }

在我們的實現(xiàn)中,只需提供鎖定utxo的公鑰以及一串描述字符串即可,最后設(shè)置交易的txId,完成coinbase交易的創(chuàng)建。

也提供了識別coinbase交易的方法:

public static isCoinbaseTx(tx: Transaction){
    if(tx.$inputTxs.length == 1 && tx.$inputTxs[0].$outputIndex == -1 && tx.$inputTxs[0].$txId == ""){
        return true;
    }else{
        return false;
    }
}

至此,coinbase交易就完成了,這是最簡單的一種交易,并沒有涉及到轉(zhuǎn)賬方,也就是交易輸入。

轉(zhuǎn)賬交易

使用BTC就避免不了轉(zhuǎn)賬,轉(zhuǎn)賬事務(wù)在utxo模型的實現(xiàn)就是添加了一筆Transaction到某個區(qū)塊而已。每一筆交易都需要交易輸入和交易輸出,因此在BTC中,轉(zhuǎn)賬的核心就是找到轉(zhuǎn)賬方的utxo進(jìn)行消費,同時將指定數(shù)量的BTC劃到指定的消費輸出上,如果仍有剩余,則找零至自己的消費輸出。

// 創(chuàng)建轉(zhuǎn)賬交易
public static createTransaction(from: string, fromPubkey: string, fromKey: string, to: string, toPubkey: string, coin: number){
    let outputs = this.findUTXOToTransfer(fromKey, coin);
    console.log(`UTXOToTransfer: ${JSON.stringify(outputs)}, from: ${from} to ${to} transfer ${coin}`)
    let inputTx = [], sum = 0, outputTx = [];
    outputs.forEach((o)=>{
        sum += o.$value;
        inputTx.push(new Input(o.$txId,o.$index,fromKey));
    });

    if(sum < coin){
        throw Error(`余額不足,轉(zhuǎn)賬失敗! from ${from} to ${to} transfer ${coin}btc, but only have ${sum}btc`);
    }

    // 公鑰鎖住腳本
    outputTx.push(new Output(coin,toPubkey));
    if(sum > coin){
        outputTx.push(new Output(sum-coin,fromPubkey));
    }
    let tx = new Transaction("",inputTx,outputTx);
    tx.setTxId();
    return tx;
}   

創(chuàng)建一個交易,需要提供轉(zhuǎn)賬方的地址(公鑰哈希)、轉(zhuǎn)賬方的公鑰和私鑰、接收方的地址、接收方的公鑰以及轉(zhuǎn)賬的BTC數(shù)量。這筆交易由轉(zhuǎn)賬發(fā)發(fā)起,因此需要提供轉(zhuǎn)賬方的私鑰進(jìn)行解鎖腳本。

首先,通過 findUTXOToTransfer 找到滿足轉(zhuǎn)賬數(shù)量的可用的utxo,它需要提供轉(zhuǎn)賬方的私鑰以及轉(zhuǎn)賬數(shù)量;
接下來根據(jù)獲得的可用utxo,進(jìn)行創(chuàng)建對應(yīng)的交易輸入;
然后用接收方的公鑰加密交易輸出,同時如果有余額的化找零給自己,用自己的公鑰加密;
最后根據(jù)得到的交易輸入與交易輸出,創(chuàng)建一筆交易,計算txId,加入到區(qū)塊中(我們的demo是在單機(jī)下進(jìn)行模擬,并未實現(xiàn)多播),等待挖礦。

轉(zhuǎn)賬的核心在于 findUTXOToTransfer,在findUTXOToTransfer中,通過調(diào)用 getAllUnspentOutputTx拿到所有的可用的utxo,并篩選出滿足給定數(shù)量BTC的utxo。

public static getAllUnspentOutputTx(secreteKey: string): Array{
    let outputIndexHash: Object = this.getAllSpentOutput(secreteKey);
    let unspentOutputsTx = [];
    let keys = Object.keys(outputIndexHash);
    let block = BlockDao.getSingletonInstance().getBlock(chain.$lastACKHash);
    while(block && block instanceof Block){
        block.$txs && block.$txs.forEach((tx)=>{
            if(keys.includes(tx.$txId)){
                tx.$outputTxs.forEach((output,i)=>{
                    // 過濾已消費的output
                    if(i == outputIndexHash[tx.$txId])
                        return;
                    
                    if(output.canUnlock(secreteKey)){
                        unspentOutputsTx.push(tx);
                    }    
                });
            }else{
                for(let i=0,len=tx.$outputTxs.length;i

在getAllUnspentOutputTx中,通過 getAllSpentOutput 遍歷本地持久化的區(qū)塊鏈,拿到所有的可供消費utxo,這些utxo并不僅僅屬于轉(zhuǎn)賬方,因此需要在針對每個utxo嘗試進(jìn)行驗證邏輯,即output.canUnlock(secreteKey)。驗證通過則證明這是屬于轉(zhuǎn)賬方的BTC,可以用于交易。

在getAllSpentOutput中,通過遍歷每一個交易輸入獲取它指向前面交易的某個utxo來得到所有的utxo,當(dāng)然對于coinbase交易我們無法找到他的交易輸入,因此會進(jìn)行過濾。

至此,utxo的轉(zhuǎn)賬流程已經(jīng)完成,下面需要做的就是把這比交易加入到區(qū)塊中了,這已不是本文的核心。

尾聲

本文所講的utxo示例是基于作者對BTC實現(xiàn)的基礎(chǔ)上的簡單實現(xiàn),有不當(dāng)之處還請讀者指出。另外,本文的代碼開源在 https://github.com/royalrover... 的 feature/utxo分支 上,希望大家一起提建議!

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/93840.html

相關(guān)文章

  • Node.js買賣比特 教程

    摘要:完整的步驟如下檢查比特幣或的余額,錢包地址。比特幣的到帳時間是個區(qū)塊的高度,約分鐘。 通過 Nodejs 買賣Bitcoin showImg(https://segmentfault.com/img/remote/1460000018771566?w=1200&h=659); Github Repo 方案一: 通過ExinCore API進(jìn)行幣幣交易 Exincore 提供了基于Mix...

    Airy 評論0 收藏0
  • Nodejs 比特開發(fā)教程: 創(chuàng)建比特錢包

    摘要:下面的代碼,可以讀取比特幣錢包余額網(wǎng)內(nèi)免手續(xù)費的,并且即時確認(rèn)任何幣在內(nèi)部的交易,都是無手續(xù)費的,并且立刻到賬。 基于Mixin Network的 Nodejs 比特幣開發(fā)教程: 創(chuàng)建比特幣錢包 showImg(https://segmentfault.com/img/remote/1460000018771566?w=1200&h=659);我們已經(jīng)創(chuàng)建過一個回復(fù)消息的機(jī)器人和一個能...

    caozhijian 評論0 收藏0
  • Python生成以太坊和比特vanity虛榮地址

    摘要:分享一些以太坊比特幣等區(qū)塊鏈相關(guān)的交互式在線編程實戰(zhàn)教程以太坊,主要是針對工程師使用進(jìn)行區(qū)塊鏈以太坊開發(fā)的詳解。這里是原文如何用為以太坊和比特幣生成虛擬地址 今天,我們將編寫一個非常簡單的python腳本來生成虛榮地址,這些地址是以某個短語或字母序列開頭的加密貨幣地址。該過程涉及生成私鑰并檢查目標(biāo)短語的地址,直到找到滿意的地址。 安裝包 首先,我們需要安裝一些可以執(zhí)行計算的軟件包,以便...

    MAX_zuo 評論0 收藏0
  • 如何理解比特和區(qū)塊鏈?

    摘要:比特幣區(qū)塊鏈無疑是當(dāng)今業(yè)界的最熱門的。目前,每個成功的礦工獲得可能每年更換一次或通過比特幣社區(qū)決策作為成功向區(qū)塊鏈添加一塊交易的獎勵。填寫其他詳細(xì)信息,例如比特幣金額和可選說明。 比特幣區(qū)塊鏈無疑是當(dāng)今業(yè)界的最熱門的。通過這篇博客,我將盡力向大家介紹加密貨幣比特幣的概念,以及它如何創(chuàng)造我們稱之為區(qū)塊鏈的革命性技術(shù)。 這個問題經(jīng)常引起混淆。這篇文章可以快速解釋和清理這方面的混亂! 什么是...

    Kosmos 評論0 收藏0

發(fā)表評論

0條評論

2json

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<