±à¼ÍƼö: |
±¾ÎÄÀ´×ÔÓÚ²©¿ÍÔ°£¬ÎÄÕÂËù½²µÄÊÇBTCÖеÄutxoÄ£ÐÍ£¬UTXOµÄnode.jsʵÏÖÖеĽ»Ò×ÊäÈ룬Êä³ö£¬Ò»±Ê½»Ò×£¬coinbase½»Ò×£¬×ªÕ˽»Òס£ |
|
BTCÖеÄutxoÄ£ÐÍ
BTCÖÐÒýÈëÁËÐí¶à´´ÐµĸÅÄîÓë¼¼Êõ£¬Çø¿éÁ´¡¢PoW¹²Ê¶¡¢RSA¼ÓÃÜ¡¢ÃÈÑ¿½×¶ÎµÄÖÇÄܺÏÔ¼µÈÃû´ÊÊǾ³£±»È¦ÄÚÈËËùÌá¼°£¬³ÏÈ»ÕâЩ´´ÐµÄʵÏÖʹµÃBTC±ä³ÉÁËÒ»ÖÖÓпɿ¿ÐԺͰ²È«ÐÔ±£Ö¤µÄ·â±ÕÉú̬ϵͳ£¬µ«ÊÇÔÚÕâ¸öBTCÉú̬ÖÐÈç¹ûûÓдîÅäÇø¿éÁ´Ä£Ê½µÄתÕËÄ£¿é£¬ÄÇô»õ±ÒµÄÁ÷ͨÊôÐÔÒ²¾ÍÎÞ´Ó̸ÆðÁË¡£ÈôҪʵÏÖתÕ˽»Ò×Ä£¿é£¬
¡°ÊÇ·ñ²ÉÓô«Í³µÄÕË»§Ä£ÐÍʵÏÖ½»Ò×£»ÈçºÎÔÚÇø¿éÁ´ÉÏ´æ´¢½»Ò×ÐÅÏ¢£¬ÈçºÎʵÏÖÐÅϢѹËõ£»ÈçºÎÑéÖ¤½»Ò×ÐÅÏ¢£»ÏµÍ³µÄ×î´ó½»Òײ¢·¢Á¿¡±µÈÎÊÌâȷʵֵµÃ˼¿¼¡£
BTCÒ»Ò»½â¾öÁËÕâЩ£¬Ëü·ÅÆúÁË´«Í³µÄ»ùÓÚÕË»§µÄ½»Ò×Ä£ÐÍ£¬¶øÊDzÉÓûùÓÚÇø¿éÁ´´æ´¢µÄutxo£¨unspent
transaction output£©Ä£ÐÍ¡£±ÊÕß³¢ÊÔ·ÖÎöÁËΪʲô²»Ê¹Óô«Í³µÄÕË»§Ä£ÐÍ£º
1.BTCµÄ´æ´¢µ¥ÔªÎªÇø¿éÁ´£¬Çø¿éÁ´µÄÊý¾Ý½á¹¹±¾ÖÊÉÏÊǵ¥ÏòÁ´±í£¬Ëü²¢²»ÊÇ´«Í³µÄ¹ØÏµÐÍÊý¾Ý¿â£¬ÎÞ·¨Ð½¨ÕË»§±í
2.´æ´¢Ñ¹Á¦¡£Èç¹û²ÉÓô«Í³µÄ·½Ê½£¬ÔòÕË»§±í»áËæ×Åʱ¼äµÄÍÆÒÆ²»Í£µØÔö´ó£¬ÎªºóÐøµÄ±íµÄ·ÖƬÓ뱸·ÝÔì³ÉºÜ´óÀ§ÄÑ
3.Ò×Ôì³ÉÒþ˽й¶¡£ÕË»§±íµÄÐÅÏ¢»áÖ±¹ÛµÄ±©Â¶Óà¶îµÈÃô¸ÐÐÅÏ¢
utxoÄ£ÐÍÔòºÜÓм¼ÇɵıÜÃâÁËÕâЩ£¬ÔÚutxoÄ£ÐÍÏÂʵÏÖµÄÿһ±Ê½»Ò×£¬¶¼²»ÐèÒªÏÔʽµÄÌṩתÕ˵ØÖ·ºÍ½ÓÊÕµØÖ·£¨utxoÖÐûÓÐÕË»§£¬Ò²²»ÐèÒªÌṩµØÖ·£©£¬Ö»ÐèÌṩÕâ±È½»Ò×µÄ
½»Ò×ÊäÈë ºÍ ½»Ò×Êä³ö ¼´¿É£¬¶ø½»Ò×ÊäÈëÓë½»Ò×Êä³öÓÖÊÇʲô£¿
½»Ò×ÊäÈëÖ¸ÏòÒ»±Ê½»Ò×Êä³ö£¬¶øÇÒ ¡°Õâ±Ê½»Ò×Êä³öÊÇ¿ÉÒÔ¹©×ªÕËÕßÏû·ÑµÄ£¬Òò´ËÕâ±Ê½»Ò×Êä³öÒ²±»³Æ×÷utxo£¨Î´»¨·Ñ½»Ò×Êä³ö£©¡±£¬Ëü°üÀ¨¡°Ä³Ò»±Ê½»Òס¢Ö¸ÏòÕâ±Ê½»Ò×µÄij¸ö¿ÉÓý»Ò×Êä³öµÄË÷ÒýÖµºÍÒ»¸ö½âËø½Å±¾¡±¡£Õâ¸ö½âËø½Å±¾ÓÃÀ´Ñé֤ij±Ê¿ÉÓõÄÏû·ÑÊä³öÊÇ·ñ¿ÉÒÔ±»Ìṩ½âËø½Å±¾µÄÈËËùʹÓá£
½»Ò×Êä³öÔòÊÇ´æ´¢BTC¡°Óà¶î¡±µÄÒ»¸öÊý¾Ý½á¹¹£¬Ëü¹ãÒåÉϰüÀ¨Á½²¿·Ö£ºBTCµÄÊýÁ¿ºÍÒ»¸öËø¶¨½Å±¾¡£
BTCµÄÊýÁ¿¿ÉÒÔÀí½âΪÓà¶î£¬±íʾÕâ±Ê½»ÒײúÉúµÄ½á¹û£»¶øËø¶¨½Å±¾ÔòÊÇÓÃijÖÖËã·¨Ëø¶¨Õâ¸öBTCÓà¶î£¬Ö±µ½Ä³ÈË¿ÉÒÔÌṩ½âËø¸Ã½Å±¾µÄÊý¾ÝÔ¿³×£¬Õâ±ÈÊý¶îBTC²Å»á±»Õâ¸öÈËËùÏû·Ñ¡£
´ÓÕâ¸ö½Ç¶È¿´£¬Ò»±Ê½»Ò×»á°üº¬Èô¸É¸ö½»Ò×ÊäÈ룬ͬʱ²úÉúÈô¸É¸ö½»Ò×Êä³ö¡£ÕâЩ½»Ò×ÊäÈë¶¼»áÖ¸Ïò֮ǰij±Ê½»Ò×µÄδ±»Ïû·ÑÊä³ö£¨utxo£©£¬²¢Ìṩ¸÷×ԵĽâËø½Å±¾ÒÔÖ¤Ã÷ÕâЩutxoÀïµÄBTCÊÇÊôÓÚתÕË·½£»Í¬Ê±½«×ªÕ˲úÉúµÄËùÓн»Ò×Êä³öÓöÔÓ¦·½µÄ¹«Ô¿½øÐмÓÃÜ£¨´Ë´¦ÊÇΪÁ˸üºÃµÄÀí½â²Å½âÊÍΪ¹«Ô¿¼ÓÃÜ£¬ÊµÖÊÉÏÊǹ«Ô¿¹þÏ££¬¼´btcµØÖ·½øÐÐÄæÏòbase58±àÂëµÄÒ»¶Î×Ö·û´®£©£¬Ëø¶¨Õ⼸±Ê½»Ò×Êä³ö£¬µÈ´ý½»Ò×ÊäÈëÖеĽâËø½Å±¾½âËø¡£

ËùÒÔ£¬BTCûÓÐÕË»§µÄ¸ÅÄËùÓеġ°Óà¶î¡±¶¼ÔÚÇø¿éÁ´ÉÏ£¬²»¹ýÕâЩÓà¶î¶¼ÒѾ±»¼ÓÃÜÁË£¬Ö»ÓÐÌṩ˽ԿºÍÇ©ÃûµÄÈ˲ſÉÒÔʹÓöÔÓ¦µÄutxoµÄÓà¶î£¬Òò´ËÕâ¾ÍÊÇΪʲôBTC³ÖÓÐÕß±ØÐë±£´æºÃ×Ô¼ºµÄ˽ԿµÄÔÒò¡£
UTXOµÄnode.jsʵÏÖ
½»Ò×ÊäÈë
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;
}
// ·´ÐòÁл¯£¬½øÐÐÀàÐÍת»»
public static createInputsFromUnserialize(objs:
Array<Input>){
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±êʶ ¡°Ä³¸ö¿ÉÓõÄutxoËùÊôµÄ½»Òס±£¬ÊÇÒ»´®sha256±àÂëµÄ×Ö·û´®£»
outputIndex±íʾ ¡°Õâ¸ö¿ÉÓõÄutxoÔÚ¶ÔÓ¦½»Ò×µÄÐòºÅÖµ¡±£»
unlockScriptÔòÊǽâËø½Å±¾£¬´Ë´¦²¢Î´ÍêÈ«°´ÕÕBTCµÄÔÐÍȥʵÏÖ£¬¶øÊǼòµ¥µÄÑé֤ʹÓÃÕßµÄ˽ԿÀ´ÊµÏÖ¼øÈ¨£¬ÔÀíÉÏÈÔ×ñ´ÓBTCµÄ˼Ïë¡£
½»Ò×Êä³ö
import * as
rsaConfig from '../../rsa.json';
export class Output {
private value: number;
// Ëø¶¨½Å±¾£¬ÐèҪʹÓÃUTXO¹éÊôÕßÓÃ˽Կ½øÐÐÇ©Ãûͨ¹ý
// µ±½âËøUTXO³É¹¦ºó£¬´ËUTXO±äΪÏÂÒ»¸ö½»Ò׵Ľ»Ò×ÊäÈ룬ͬʱʹÓýÓÊÕ·½µÄµØÖ·£¨¹«Ô¿£©Ëø¶¨±¾´Î½»Ò׵Ľ»Ò×Êä³ö£¬
// µÈ´ý½ÓÊÕ·½Ê¹ÓÃ˽ԿǩÃûʹÓøÃUTXO
// Òò´Ë£¬btcûÓÐÕË»§µÄ¸ÅÄËùÓеġ°Ç®¡±ÓÉ×Ô¼ºµÄ¹«Ô¿Ëù¼ÓÃܱ£´æ£¬Ö»ÓÐÓÃ×Ô¼ºµÄ˽Կ²ÅÄÜʹÓÃÕâЩǮ£¨¼´½âËøÁËUTXOµÄ½âËø½Å±¾£©
private lockScript: string;
// ¸ÃÊôÐÔ½ö½öÔÚ½»Ò×ʱʹÓã¬ÉèÖÃÊôÐÔ
private txId: string;
// ¸ÃÊôÐÔ½ö½öÔÚ½»Ò×ʱʹÓã¬ÉèÖÃÊôÐÔ
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;
}
// ·´ÐòÁл¯£¬½øÐÐÀàÐÍת»»
public static createOnputsFromUnserialize(objs:
Array<Output>){
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ÊôÐÔ±êʶµ±Ç°utxoµÄÓà¶î£¬¼´BTC¸öÊý£»
lockScriptÊôÐÔÎªËø¶¨½Å±¾£¬ÔÚÎÒÃǵļòÒ×ʵÏÖÖоÍΪ½ÓÊÕ·½µÄ¹«Ô¿£¬²¢²»ÊÇBTCÖеÄÄæ²¨À¼Ê½£¬µ«´óÌåÔÀíÏàͬ£¬¶¼ÐèÒªÌṩ˽ԿÀ´½øÐнâÃÜ¡£
Ò»±Ê½»Ò×
Ò»±Ê½»Ò×£¬°üº¬ÁËÈô¸É¸ö½»Ò×ÊäÈëºÍ½»Ò×Êä³ö£¬Í¬Ê±Ò²ÌṩÁËÒ»¸ötxIdΨһµÄ±êʶÕâ±È½»Òס£´Ó½á¹¹ÉÏ¿´ÊÇÕâÑùµÄ£º
export class
Transaction {
private txId: string;
private inputTxs: Array<Input>;
private outputTxs: Array<Output>;
constructor(txId: string, inputs: Array<Input>,
outputs: Array<Output>){
this.txId = txId;
this.inputTxs = inputs;
this.outputTxs = outputs;
}<>br
public get $txId(): string {
return this.txId;
}
public set $txId(value: string) {
this.txId = value;
}
public get $inputTxs(): Array<Input>
{
return this.inputTxs;
}
public set $inputTxs(value: Array<Input>)
{
this.inputTxs = value;
}
public get $outputTxs(): Array<Output>
{
return this.outputTxs;
}
public set $outputTxs(value: Array<Output>)
{
this.outputTxs = value;
}
/*
1.½»Ò׽ṹ¸÷×Ö¶ÎÐòÁл¯Îª×Ö½ÚÊý×é
2.°Ñ×Ö½ÚÊý×鯴½ÓΪ֧¸¶´®
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µÄ¼ÆËãÕâÀﲢûÓÐÑϸñ°´ÕÕBTCʵÏÖµÄÄÇÑù½øÐмÆË㣬¶øÊǼòµ¥µÄ½øÐжÔÏóÐòÁл¯½øÐÐÒ»´Îsha256¡£
coinbase½»Ò×
ÎÒÃǶ¼ÖªµÀµÃµ½±ÈÌØ±ÒÐèÒªÍÚ¿ó£¬ÆäʵÍÚ¿óÒ²ÊôÓÚÒ»ÖÖ½»Ò×£¬²»¹ýÊÇÒ»ÖÖûÓÐÈ·¶¨½»Ò×ÊäÈëµÄÒ»ÖÖ½»Ò×£¬ËüÒ²±»³Æ×÷coinbase½»Òס£coinbase½»Ò×ÔÚÿһ¸öÇø¿éÖж¼»á´æÔÚ£¬ËüµÄ×ܶî°üÀ¨ÁËϵͳÕë¶Ô¿ó¹¤´ò°ü½»Ò×¹ý³ÌµÄ½±ÀøÒÔ¼°ÆäËûתÕË·½ÌṩµÄÊÖÐø·Ñ£¬ÈçÏÂͼ£º

Òò´Ë£¬´´½¨Ò»¸ö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;
} |
ÔÚÎÒÃǵÄʵÏÖÖУ¬Ö»ÐèÌá¹©Ëø¶¨utxoµÄ¹«Ô¿ÒÔ¼°Ò»´®ÃèÊö×Ö·û´®¼´¿É£¬×îºóÉèÖý»Ò×µÄtxId£¬Íê³Écoinbase½»Ò׵Ĵ´½¨¡£
Ò²ÌṩÁËʶ±ð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½»Ò×¾ÍÍê³ÉÁË£¬ÕâÊÇ×î¼òµ¥µÄÒ»ÖÖ½»Ò×£¬²¢Ã»ÓÐÉæ¼°µ½×ªÕË·½£¬Ò²¾ÍÊǽ»Ò×ÊäÈë¡£
תÕ˽»Ò×
ʹÓÃBTC¾Í±ÜÃâ²»ÁËתÕË£¬×ªÕËÊÂÎñÔÚutxoÄ£Ð͵ÄʵÏÖ¾ÍÊÇÌí¼ÓÁËÒ»±ÊTransactionµ½Ä³¸öÇø¿é¶øÒÑ¡£Ã¿Ò»±Ê½»Ò×¶¼ÐèÒª½»Ò×ÊäÈëºÍ½»Ò×Êä³ö£¬Òò´ËÔÚBTCÖУ¬×ªÕ˵ĺËÐľÍÊÇÕÒµ½×ªÕË·½µÄutxo½øÐÐÏû·Ñ£¬Í¬Ê±½«Ö¸¶¨ÊýÁ¿µÄBTC»®µ½Ö¸¶¨µÄÏû·ÑÊä³öÉÏ£¬Èç¹ûÈÔÓÐÊ£Ó࣬ÔòÕÒÁãÖÁ×Ô¼ºµÄÏû·ÑÊä³ö¡£
Hello World!//
´´½¨×ªÕ˽»Ò×
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(`Óà¶î²»×㣬תÕËʧ°Ü! 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;
} |
´´½¨Ò»¸ö½»Ò×£¬ÐèÒªÌṩתÕË·½µÄµØÖ·£¨¹«Ô¿¹þÏ££©¡¢×ªÕË·½µÄ¹«Ô¿ºÍ˽Կ¡¢½ÓÊÕ·½µÄµØÖ·¡¢½ÓÊÕ·½µÄ¹«Ô¿ÒÔ¼°×ªÕ˵ÄBTCÊýÁ¿¡£Õâ±Ê½»Ò×ÓÉתÕË·¢·¢Æð£¬Òò´ËÐèÒªÌṩתÕË·½µÄ˽Կ½øÐнâËø½Å±¾¡£
Ê×ÏÈ£¬Í¨¹ý findUTXOToTransfer ÕÒµ½Âú×ãתÕËÊýÁ¿µÄ¿ÉÓõÄutxo£¬ËüÐèÒªÌṩתÕË·½µÄ˽ԿÒÔ¼°×ªÕËÊýÁ¿£»
½ÓÏÂÀ´¸ù¾Ý»ñµÃµÄ¿ÉÓÃutxo£¬½øÐд´½¨¶ÔÓ¦µÄ½»Ò×ÊäÈ룻
È»ºóÓýÓÊÕ·½µÄ¹«Ô¿¼ÓÃܽ»Ò×Êä³ö£¬Í¬Ê±Èç¹ûÓÐÓà¶îµÄ»¯ÕÒÁã¸ø×Ô¼º£¬ÓÃ×Ô¼ºµÄ¹«Ô¿¼ÓÃÜ£»
×îºó¸ù¾ÝµÃµ½µÄ½»Ò×ÊäÈëÓë½»Ò×Êä³ö£¬´´½¨Ò»±Ê½»Ò×£¬¼ÆËãtxId£¬¼ÓÈëµ½Çø¿éÖУ¨ÎÒÃǵÄdemoÊÇÔÚµ¥»úϽøÐÐÄ£Ä⣬²¢Î´ÊµÏֶಥ£©£¬µÈ´ýÍÚ¿ó¡£
תÕ˵ĺËÐÄÔÚÓÚ findUTXOToTransfer£¬ÔÚfindUTXOToTransferÖУ¬Í¨¹ýµ÷ÓÃ
getAllUnspentOutputTxÄõ½ËùÓеĿÉÓõÄutxo£¬²¢É¸Ñ¡³öÂú×ã¸ø¶¨ÊýÁ¿BTCµÄutxo¡£
public static
getAllUnspentOutputTx(secreteKey: string): Array<Transaction>{
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<len;i++){
let output = tx .$outputTxs[i];
if(output.canUnlock(secreteKey)){
unspentOutputsTx .push(tx);
break;
}
}
}
});
block = BlockDao.getSingletonInstance ().getBlock
(block.$prevHash);
}
return unspentOutputsTx;
} |
ÔÚgetAllUnspentOutputTxÖУ¬Í¨¹ý getAllSpentOutput ±éÀú±¾µØ³Ö¾Ã»¯µÄÇø¿éÁ´£¬Äõ½ËùÓеĿɹ©Ïû·Ñutxo£¬ÕâЩutxo²¢²»½ö½öÊôÓÚתÕË·½£¬Òò´ËÐèÒªÔÚÕë¶Ôÿ¸öutxo³¢ÊÔ½øÐÐÑéÖ¤Âß¼£¬¼´output.canUnlock(secreteKey)¡£Ñé֤ͨ¹ýÔòÖ¤Ã÷ÕâÊÇÊôÓÚתÕË·½µÄBTC£¬¿ÉÒÔÓÃÓÚ½»Òס£
ÔÚgetAllSpentOutputÖУ¬Í¨¹ý±éÀúÿһ¸ö½»Ò×ÊäÈë»ñÈ¡ËüÖ¸ÏòÇ°Ãæ½»Ò×µÄij¸öutxoÀ´µÃµ½ËùÓеÄutxo£¬µ±È»¶ÔÓÚcoinbase½»Ò×ÎÒÃÇÎÞ·¨ÕÒµ½ËûµÄ½»Ò×ÊäÈ룬Òò´Ë»á½øÐйýÂË¡£
ÖÁ´Ë£¬utxoµÄתÕËÁ÷³ÌÒѾÍê³É¡£ |