花一个晚上看完了btc白皮书,借助AI理解了一下btc转账。

第一个框的交易指定了Owner0 将一笔UTXO(Unspent Transaction Output)指定给了Owner 1的公钥,这个时候如果Owner1想要使用这笔UTXO,则需要使用自己的私钥生成一段签名,整个网络可以验证这个签名是否正确。 结合代码看,首先将UTXO作为输入,验证UTXO签名是否正确(即Owner 0 的签名),将接收BTC的地址作为输出,使用Owner的私钥对其进行签名,再将其放到最后一个区块内即可。 基于非对称加密,可以很容易使用公钥验证一个签名是否是由正确的私钥签发的,进而使得私钥的所有人证明其所有权,
const utxos = await getUTXOs(senderAddress);
...
const keyPair = ECPair.fromWIF(senderPrivateKey, network);
...
let inputAmount = BigInt(0);
const psbt = new bitcoin.Psbt({ network });
psbt.setVersion(2);
psbt.setLocktime(0);
const utxo = utxos[0];
inputAmount += BigInt(utxo.value);
const txid = utxo.tx_hash_big_endian;
const rawTxHex = await getRawTxHex(txid);
if (rawTxHex) {
// 非 witness 输入:需要传入整个前置交易的 raw hex
psbt.addInput({
hash: txid,
index: utxo.tx_output_n,
nonWitnessUtxo: Buffer.from(rawTxHex, 'hex'),
});
} else {
// 如果无法获取 raw tx,可以尝试用 witnessUtxo(仅对 segwit 输出有效)
psbt.addInput({
hash: txid,
index: utxo.tx_output_n,
witnessUtxo: {
script: Buffer.from(utxo.script, 'hex'),
value: Number(utxo.value), // witnessUtxo.value should be a number (satoshis)
},
});
}
psbt.addOutput({
script: bitcoin.address.toOutputScript(recipientAddress, network),
value: amountToSend, // must be BigInt
});
psbt.addOutput({
script: bitcoin.address.toOutputScript(senderAddress, network),
value: inputAmount - amountToSend - BigInt(500), // 找零,减去手续费(假设1000聪)
});
// 签名并 finalise
const validator = (
pubkey,
msghash,
signature,
) => ECPair.fromPublicKey(pubkey, network).verify(msghash, signature);
psbt.signInput(0, keyPair);
try {
for (let i = 0; i < psbt.inputCount; i++) {
psbt.validateSignaturesOfInput(i, validator);
console.log(`Input ${i} signature valid`);
}
} catch (e) {
console.warn('Signature validation failed or not applicable:', e.message || e);
}
try {
psbt.finalizeAllInputs();
} catch (e) {
console.error('Failed to finalize inputs:', e.message || e);
return;
}
const txHex = psbt.extractTransaction().toHex();
UTXO模型是BTC网络用来间接计算账户余额的方式,传统中心化交易依赖于一个中心实体记录每一个账户的消费,入账及余额,通过这个中心化实体用户才能知道自己的消费记录情况,用户之间是看不到对方的消费等记录的,对于去中心化的区块链来说一大要点就是透明:每个人都可以在区块上面验证某个信息是否正确,这也就要求不能依赖于中心化实体,在BTC中UTXO首次被实现。
[
{
tx_hash_big_endian: '9bd090ad9a846428f4d060463ca13f878fb78ab0d66d7019941fda6ae7e74f4e',
tx_hash: '4e4fe7e76ada1f9419706dd6b08ab78f873fa13c4660d0f42864849aad90d09b',
tx_output_n: 28,
script: '76a9146b12dbf14da1e874dc8d962d661bd3abe5f910a588ac',
value: 17000,
value_hex: '4268',
confirmations: 160,
tx_index: 2755363202751299
}
]
UTXO结构
UTXO全称Unspent Transaction Output,未花费交易输出,在BTC网络中每个地址(钱包)没有余额的概念,那么想要花一笔钱该如何做呢。
当想花费时需要将一笔或者多笔未花费的UTXO可以作为新交易中的输入,一笔交易可能有多个输入和多个输出,由于没有余额的概念那么自然没有找零的概念,假设我想买价值0.5BTC的东西,我有一笔1btc的UTXO,那么此时应该如何做呢。
对于不能一笔花完的开销来说,需要添加一个输出,里面放入自己钱包的公钥,完成交易后,自己钱包会多出一笔未花费的UTXO,实现了间接找零。
以链上一笔交易来说明,tx:77e6773b1cfc38bca5c6ea649ba0e0c1985dc55c00f65284362f0ad79b741ecc,使用代码对其解码,其拥有一笔输入,和多个输出,输入减去输出就是给矿工的fee。
{
"network": "bitcoin mainnet",
"txid": "77e6773b1cfc38bca5c6ea649ba0e0c1985dc55c00f65284362f0ad79b741ecc",
"version": 1,
"size_bytes": 391,
"weight": 802,
"vsize": 201,
"locktime": {
"type": "blockHeight",
"value": 0
},
"vin_count": 1,
"vout_count": 2,
"inputs": [
{
"index": 0,
"prevout": {
"txid": "b145aad702e266d74dffa743a54639101e265b9df9fcfae3d8fce1c194a282e7",
"vout": 2
},
"sequence": 4294967293,
"rbfLikely": true,
"scriptSigHex": "",
"witness": [
{
"index": 0,
"hex": "",
"len": 0
},
{
"index": 1,
"hex": "48,68,2,32,99,127,45,212,211,58,92,53,118,21,122,22,113,230,97,197,89,110,44,164,32,109,37,188,205,218,99,170,193,108,162,54,2,32,122,235,76,115,81,62,230,176,199,161,166,251,224,187,129,123,29,161,18,81,102,224,26,218,140,64,193,187,6,37,207,203,1",
"len": 71
},
{
"index": 2,
"hex": "48,68,2,32,70,149,209,74,159,228,5,72,211,191,0,158,60,171,152,217,118,153,162,205,30,30,28,118,191,252,14,30,240,182,250,120,2,32,64,136,99,29,211,184,215,38,52,63,46,87,204,194,28,210,168,97,161,180,143,43,86,151,21,97,199,117,239,108,44,221,1",
"len": 71
},
{
"index": 3,
"hex": "82,33,3,120,197,249,69,7,142,221,73,97,2,213,147,83,214,1,126,126,212,23,234,187,117,42,58,229,164,228,155,20,44,85,166,33,2,237,87,136,14,74,15,140,231,227,169,247,56,151,44,25,1,112,203,115,84,222,17,214,109,63,136,147,52,197,220,63,62,33,2,225,38,37,255,92,147,211,55,179,187,185,201,80,106,241,81,50,45,45,115,46,219,98,200,255,88,79,42,196,92,250,252,83,174",
"len": 105
}
]
}
],
"outputs": [
{
"index": 0,
"value_sats": "162510",
"value_btc": 0.0016251,
"scriptPubKeyHex": "0,32,123,184,245,128,42,228,70,190,78,95,125,222,56,124,161,98,79,174,224,154,134,67,168,193,111,248,125,244,35,94,37,132",
"scriptType": "p2wsh",
"address": "bc1q0wu0tqp2u3rtunjl0h0rsl9pvf86acy6sep63st0lp7lgg67ykzqeq89pn"
},
{
"index": 1,
"value_sats": "1610937",
"value_btc": 0.01610937,
"scriptPubKeyHex": "0,32,26,66,192,48,236,160,69,158,169,57,88,142,36,24,145,133,81,169,4,166,150,159,112,105,52,139,246,54,80,174,22,75",
"scriptType": "p2wsh",
"address": "bc1qrfpvqv8v5pzea2fetz8zgxy3s4g6jp9xj60hq6f530mrv59wze9se9a3md"
}
]
}
代码: https://github.com/Chestnuts4/web3learning