隔離見(jiàn)證的新簽名算法
Pay-to-Witness-Script-Hash (P2WSH)
區(qū)塊鏈中的隔離見(jiàn)證是什么匈庭?
深入比特幣原理(十五)——隔離見(jiàn)證(Segregated Witness)
交易結(jié)構(gòu)的區(qū)別
交易原始json數(shù)據(jù):
1帚呼、以1為開(kāi)頭的地址到以1為開(kāi)頭的地址
2暴备、以1為開(kāi)頭的地址到以3為開(kāi)頭的地址
3、以1為開(kāi)頭的地址到以bc為開(kāi)頭的地址
4央碟、以3為開(kāi)頭的地址到以1為開(kāi)頭的地址
5酱固、以3為開(kāi)頭的地址到以3為開(kāi)頭的地址
6、以3為開(kāi)頭的地址到以bc為開(kāi)頭的地址
7兔跌、以bc為開(kāi)頭的地址到以1為開(kāi)頭的地址
8、以bc為開(kāi)頭的地址到以3為開(kāi)頭的地址
9峡蟋、以bc為開(kāi)頭的地址到以bc為開(kāi)頭的地址
以bc為開(kāi)頭的地址到以bc為開(kāi)頭的地址(兩個(gè)輸入)
1坟桅、2相满、3、4桦卒、5立美、6相同
7、8方灾、9相同
Legacy交易結(jié)構(gòu):
隔離見(jiàn)證(Segregated Witness)交易結(jié)構(gòu):
對(duì)于那些沒(méi)有升級(jí)為支持隔離見(jiàn)證的節(jié)點(diǎn)來(lái)說(shuō)建蹄,他們?cè)讷@取到隔離見(jiàn)證交易時(shí)是完全感知不到的,因?yàn)閷?duì)于舊節(jié)點(diǎn)來(lái)說(shuō)裕偿,交易結(jié)構(gòu)并沒(méi)有改變洞慎。
對(duì)于升級(jí)為支持隔離見(jiàn)證的節(jié)點(diǎn)來(lái)說(shuō),他們不僅能看到屬于交易結(jié)構(gòu)中的內(nèi)容嘿棘,并且還能看到這筆交易結(jié)構(gòu)外部包含的一小塊信息劲腿,這里的信息才是隔離見(jiàn)證的信息。信息里鸟妙,包括了marker焦人、flag、witness三個(gè)部分重父。
marker和flag都是標(biāo)記花椭,marker要求必須是1個(gè)字節(jié)的0,即0x00房午,flag要求必須是1字節(jié)的非0值矿辽,目前是0x01。
witness就是隔離見(jiàn)證(SegWit)中的見(jiàn)證(Wit)郭厌。即袋倔,對(duì)交易簽名。
P2PKH交易類(lèi)型的交易折柠,如果用了隔離見(jiàn)證宾娜,是什么樣子的:
witness:
scriptSig: (empty)
scriptPubKey: 0
我們可以看到,witness部分液走,存放的是之前解鎖工具里的東西碳默。scriptSig是指原交易結(jié)構(gòu)中的解鎖工具,隔離見(jiàn)證的交易里缘眶,此處置空嘱根。scriptPubKey是指那把鎖,也就是鎖定腳本巷懈,包含兩個(gè)部分该抒,一個(gè)是0,另一個(gè)是20個(gè)字節(jié)的加密數(shù)據(jù)顶燕。
0的意思凑保,是指隔離見(jiàn)證交易的版本號(hào)是0冈爹。未來(lái)可能會(huì)支持其它版本的交易。
這樣的話欧引,當(dāng)未升級(jí)的節(jié)點(diǎn)在進(jìn)行驗(yàn)證時(shí)频伤,發(fā)現(xiàn)解鎖腳本中竟然是空的,并且鎖定腳本也沒(méi)有什么CHECK相關(guān)的操作芝此,那么舊節(jié)點(diǎn)會(huì)認(rèn)為這個(gè)地址里的幣誰(shuí)都可以花憋肖,但并不符合標(biāo)準(zhǔn)的交易類(lèi)型,于是對(duì)于這種交易來(lái)說(shuō)婚苹,他會(huì)拒絕岸更, 對(duì)于包含這種交易的區(qū)塊來(lái)說(shuō),會(huì)驗(yàn)證通過(guò)膊升。(復(fù)雜的比特幣升級(jí)分析(4)里講過(guò)為什么對(duì)交易拒絕怎炊,對(duì)區(qū)塊接受)
對(duì)于升級(jí)了的節(jié)點(diǎn),首先要驗(yàn)證鎖定腳本里開(kāi)頭是不是0廓译,如果是0评肆,判斷后面的是不是20個(gè)字節(jié)。如果是责循,再去用witness里的公鑰經(jīng)過(guò)HASH160加密后與鎖定腳本中的20字節(jié)數(shù)據(jù)對(duì)比是否一致糟港。如果一致,再用witness中的私鑰簽名與公鑰通過(guò)CHECKSIG操作進(jìn)行驗(yàn)證院仿,是否會(huì)返回TRUE。
采用P2PKH交易類(lèi)型的隔離見(jiàn)證交易稱(chēng)為P2WPKH速和,即pay-to-witness-public-key-hash歹垫。
采用P2SH交易類(lèi)型的隔離見(jiàn)證交易稱(chēng)為P2WSH,即pay-to-witness-script-hash颠放。
原文鏈接 隔離見(jiàn)證交易的結(jié)構(gòu)排惨、規(guī)則、驗(yàn)證過(guò)程
復(fù)雜的比特幣升級(jí)分析(4)
區(qū)塊分析
比特幣交易中的簽名與驗(yàn)證
比特幣原始交易解析
隔離驗(yàn)證交易解析
比特幣中對(duì)交易進(jìn)行簽名的詳細(xì)過(guò)程
腳本類(lèi)型 簽名驗(yàn)證的規(guī)則
簽名方式:
P2PKH(1), // pay to pubkey hash (aka pay to address)
P2PK(2), // pay to pubkey
P2SH(3), // pay to script hash
P2WPKH(4), // pay to witness pubkey hash
P2WSH(5), // pay to witness script hash
P2WPKHSH(6), // P2WPKH nested in P2SH
普通腳本類(lèi)型 | 隔離見(jiàn)證腳本類(lèi)型 |
---|---|
P2PKH(Pay-to-Public-Key-Hash) | P2WPKH(Pay-to-Witness-Public-Key-Hash) |
P2PK(Pay-to-Public-Key) | |
P2SH(Pay-to-Script-Hash) | P2WSH(Pay-to-Witness-Script-Hash) |
交易簽名流程
構(gòu)建交易信息:
fun buildTransaction(unspentOutput: UnspentOutput, toAddress: String, feeRate: Int, sortType: TransactionDataSortType): FullTransaction {
交易信息實(shí)體
val mutableTransaction = MutableTransaction(false)
recipientSetter.setRecipient(mutableTransaction, toAddress, unspentOutput.output.value, mapOf(), false)
添加輸入信息
inputSetter.setInputs(mutableTransaction, unspentOutput, feeRate)
lockTimeSetter.setLockTime(mutableTransaction)
添加接受地址和金額
outputSetter.setOutputs(mutableTransaction, sortType)
簽名信息
signer.sign(mutableTransaction)
return mutableTransaction.build()
}
普通交易:
/ / 秘鑰處理過(guò)程
val networkParameters = NetParamsService.getNetworkParameters(wallet.chainType)
val bytes = WalletManager.getBtcPriKey(wallet.keystore, password)
val xprv = String(bytes, Charset.forName("UTF-8"))
val xprvKey = DeterministicKey.deserializeB58(xprv, networkParameters)
val privateKey = xprvKey.privKey
val ecKey = ECKey.fromPrivate(privateKey)
val tran = Transaction(networkParameters)
val totalMoney = feeDelegate.getTotalAmount()
val amount = feeDelegate.getAmount()
val fee = feeDelegate.getFee()
val changeAmount = totalMoney - amount - fee
// 添加收賬地址和金額數(shù)據(jù)
tran.addOutput(Coin.valueOf(amount), Address.fromString(networkParameters, toAddress))
// 添加找零地址輸出
if (changeAmount > DUST_THRESHOLD) {
tran.addOutput(Coin.valueOf(changeAmount), Address.fromString(networkParameters, wallet.getAddress()))
}
// 添加輸入信息和簽名信息
for (output in feeDelegate.getOutputs()) {
val transactionOutPoint = TransactionOutPoint(networkParameters, output.vout.toLong(), Sha256Hash.wrap(output.txHash))
//這個(gè)添加簽名輸入的最后一個(gè)參數(shù)就是添加了SIGHASH_FORKID(0x40)
tran.addSignedInput(transactionOutPoint, Coin.valueOf(BigDecimal(output.amount).toLong()),
Script(NumericUtil.hexToBytes(output.scriptPubKey)), ecKey, Transaction.SigHash.ALL, true, isFork())
}
// 交易字節(jié)數(shù)據(jù)轉(zhuǎn)化
val signedHex = NumericUtil.bytesToHex(tran.bitcoinSerialize())
val txHash = NumericUtil.beBigEndianHex(Hash.sha256(Hash.sha256(signedHex)))
隔離見(jiàn)證普通交易
// 添加收賬地址和轉(zhuǎn)賬金額
mutableTransaction.recipientAddress = addressConverter.convert(toAddress)
mutableTransaction.recipientValue = value
// 添加inputs信息
fun setInputs(mutableTransaction: MutableTransaction, feeRate: Int, senderPay: Boolean, sortType: TransactionDataSortType) {
val value = mutableTransaction.recipientValue
val dust = dustCalculator.dust(changeScriptType)
val unspentOutputInfo = unspentOutputSelector.select(
value,
feeRate,
mutableTransaction.recipientAddress.scriptType,
changeScriptType,
senderPay, dust,
mutableTransaction.getPluginDataOutputSize()
)
// 對(duì)未花費(fèi)的消費(fèi)列表進(jìn)行排序
val sorter = transactionDataSorterFactory.sorter(sortType)
val unspentOutputs = sorter.sortUnspents(unspentOutputInfo.outputs)
// 添加inputs 信息并簽名
for (unspentOutput in unspentOutputs) {
mutableTransaction.addInput(inputToSign(unspentOutput))
}
mutableTransaction.recipientValue = unspentOutputInfo.recipientValue
// Add change output if needed
// 添加找零地址
unspentOutputInfo.changeValue?.let { changeValue ->
val changePubKey = publicKeyManager.changePublicKey()
val changeAddress = addressConverter.convert(changePubKey, changeScriptType)
mutableTransaction.changeAddress = changeAddress
mutableTransaction.changeValue = changeValue
}
pluginManager.processInputs(mutableTransaction)
}
// 添加outputs
fun setOutputs(transaction: MutableTransaction, sortType: TransactionDataSortType) {
val list = mutableListOf<TransactionOutput>()
transaction.recipientAddress.let {
list.add(TransactionOutput(transaction.recipientValue, 0, it.lockingScript, it.scriptType, it.string, it.hash))
}
transaction.changeAddress?.let {
list.add(TransactionOutput(transaction.changeValue, 0, it.lockingScript, it.scriptType, it.string, it.hash))
}
if (transaction.getPluginData().isNotEmpty()) {
var data = byteArrayOf(OP_RETURN.toByte())
transaction.getPluginData().forEach {
data += byteArrayOf(it.key) + it.value
}
list.add(TransactionOutput(0, 0, data, ScriptType.NULL_DATA))
}
val sorted = transactionDataSorterFactory.sorter(sortType).sortOutputs(list)
sorted.forEachIndexed { index, transactionOutput ->
transactionOutput.index = index
}
transaction.outputs = sorted
}
以上代碼基于unstoppable錢(qián)包源碼分析
錢(qián)包生成的隔離見(jiàn)證的數(shù)據(jù)
02000000000101ce846254bb6eeb32e71b8c1710da46fd91b4b9de50ba638f138e7eac7dae19be000000001716001488828e4385c9d7b31767ec24b0d8eb335cd3f13bffffffff02102700000000000017a914ec4341563a037db8ad7d5a756243d76f5d625d0a876c2200000000000017a914ec4341563a037db8ad7d5a756243d76f5d625d0a8702473044022040b0b80a733be983593eb6c22ac324c1326ef9e604cda45150f1f0c3c3a5a502022052a4c82d59c12e3a9bb0e498ade9edd4ff47a9e24fed73d7bd7234ed3b8808970121029741dc8ec4561502b884e20ef743a85e346a0aa95bb2ef2885f81f60addd620800000000
可以通過(guò)這里
附錄:
隔離見(jiàn)證由以下BIPs定義:
BIP-141隔離見(jiàn)證的主要定義
BIP-143版本0見(jiàn)證程序的交易簽名驗(yàn)證
BIP-144對(duì)等服務(wù)——新的網(wǎng)絡(luò)消息和序列化格式
BIP-145隔離見(jiàn)證(對(duì)于礦工)的 getblocktemplate 升級(jí)