Thanks a lot for this repo and your hard work.
I have learned a lot from it.
I have passed the unit test in file unitTest .
The testSignTransaction1
shows the step how to create a transaction contains a input and two outputs.
But I don't know how to create a transaction which contains two or more inputs.
Transaction toAddress is mgU6dEQBFpwdSD46Qq2MoMw1tCBi3hEmvy
, toValue is 95000000
.
And I have two inputs which hash-value-script is below:
input 1 :
hash: 2eb9d00e2448aea9601df8f4326ee6d753e80c3d261e78795da7b20bb5d451f3
value: 68000000
script: 76a9147c457cce7d24a467ff39d157d3e3c1371bf2b6c888ac
input 2:
hash: 02e7c0a97dee2f31d4fe181c735fb32f8166664f7630c713d003f584cfafb490
value: 32500000
script: 76a9147c457cce7d24a467ff39d157d3e3c1371bf2b6c888ac
Detail Link is input 1 or input 2
The privateKey(wif) in (btc testnet) is cVX5NApUtWqrJneZK2PYsjqcbJvSZVU4Wh7CEF9CQP9Qwa2pCANV
and from address is mrr3KvFX3Ekzw5Zjys7VJ1PVf3v9WDcuFq
I have tried two method.
func testSignTransaction3() {
// Transaction in testnet3
// https://api.blockcypher.com/v1/btc/test3/txs/0189910c263c4d416d5c5c2cf70744f9f6bcd5feaf0b149b02e5d88afbe78992
// build input1
let prevTxID = "2eb9d00e2448aea9601df8f4326ee6d753e80c3d261e78795da7b20bb5d451f3"
let hash = Data(Data(hex: prevTxID).reversed())
let index: UInt32 = 1
let outpoint = BTCTransaction.OutPoint(transactionHash: hash, index: index)
let subScript = Data(hex: "76a9147c457cce7d24a467ff39d157d3e3c1371bf2b6c888ac")
let inputForSign = BTCTransaction.Input(outPoint: outpoint, signatureScript: subScript, sequence: UInt32.max)
// build input2
let prevTxID2 = "02e7c0a97dee2f31d4fe181c735fb32f8166664f7630c713d003f584cfafb490"
let hash2 = Data(Data(hex: prevTxID2).reversed())
let index2: UInt32 = 0
let outpoint2 = BTCTransaction.OutPoint(transactionHash: hash2, index: index2)
let subScript2 = Data(hex: "76a9147c457cce7d24a467ff39d157d3e3c1371bf2b6c888ac")
let inputForSign2 = BTCTransaction.Input(outPoint: outpoint2, signatureScript: subScript2, sequence: UInt32.max)
// build output
let balance: Int64 = 68000000
let balance2: Int64 = 32500000
let amount: Int64 = 95000000
let fee: Int64 = 2000000
let toAddress = "mgU6dEQBFpwdSD46Qq2MoMw1tCBi3hEmvy" // https://testnet.coinfaucet.eu/en/
let toPubKeyHash = Base58.decode(toAddress).dropFirst().dropLast(4)
let privateKey = try! PrivateKey(wif: "cVX5NApUtWqrJneZK2PYsjqcbJvSZVU4Wh7CEF9CQP9Qwa2pCANV")
let fromPublicKey = privateKey.publicKey()
XCTAssertEqual(fromPublicKey.raw.hex, "03ecb24876e81293acca623d39dbc74ad23d2483e14ba2cbb86ac6d75eb5689d29")
let fromPubKeyHash = Crypto.sha256ripemd160(fromPublicKey.raw)
let lockingScript1 = Script.buildPublicKeyHashOut(pubKeyHash: toPubKeyHash)
let lockingScript2 = Script.buildPublicKeyHashOut(pubKeyHash: fromPubKeyHash)
XCTAssertEqual(lockingScript1.hex, "76a9140a6dd4fc6b19713621871f01fd9cfc37feb5026788ac")
XCTAssertEqual(lockingScript2.hex, "76a9147c457cce7d24a467ff39d157d3e3c1371bf2b6c888ac")
let sending = BTCTransaction.Output(value: amount, lockingScript: lockingScript1)
let payback = BTCTransaction.Output(value: balance + balance2 - amount - fee, lockingScript: lockingScript2)
// build signed BTCTransaction input1
let _tx = BTCTransaction(version: 1, inputs: [inputForSign, inputForSign2], outputs: [sending, payback], lockTime: 0)
let hashType: SighashType = SighashType.BTC.SINGLE
let _txHash = Crypto.doubleSHA256(_tx.bitcoinData + UInt32(hashType).littleEndian)
XCTAssertEqual(_txHash.hex, "28ab5307bb98d78a10514faa6fbbba7bc7881d5eb3f885e110c713ed40f9024a")
guard let signature: Data = try? Crypto.sign(_txHash, privateKey: privateKey) else {
XCTFail("failed to sign")
return
}
XCTAssertEqual(signature.hex, "3045022100ef6aa7c8548a62b20a0edda83c90bc7841ede71d6e745eb8fb969f8b5047f00a022024288fa32844be4fe8cdfafb487e95158202b736aa81402cb20c9b172667a3d3")
// scriptSig: <sig> <pubKey>
var unlockingScript: Data = Data([UInt8(signature.count + 1)]) + signature + UInt8(hashType)
unlockingScript += UInt8(fromPublicKey.raw.count)
unlockingScript += fromPublicKey.raw
let input = BTCTransaction.Input(outPoint: outpoint, signatureScript: unlockingScript, sequence: UInt32.max)
let input2 = BTCTransaction.Input(outPoint: outpoint2, signatureScript: unlockingScript, sequence: UInt32.max)
// build BTCTransaction
let transaction = BTCTransaction(version: 1, inputs: [input, input2], outputs: [sending, payback], lockTime: 0)
let expect = Data(hex: "0100000002f351d4b50bb2a75d79781e263d0ce853d7e66e32f4f81d60a9ae48240ed0b92e010000006b483045022100ef6aa7c8548a62b20a0edda83c90bc7841ede71d6e745eb8fb969f8b5047f00a022024288fa32844be4fe8cdfafb487e95158202b736aa81402cb20c9b172667a3d3032103ecb24876e81293acca623d39dbc74ad23d2483e14ba2cbb86ac6d75eb5689d29ffffffff90b4afcf84f503d013c730764f6666812fb35f731c18fed4312fee7da9c0e702000000006b483045022100ef6aa7c8548a62b20a0edda83c90bc7841ede71d6e745eb8fb969f8b5047f00a022024288fa32844be4fe8cdfafb487e95158202b736aa81402cb20c9b172667a3d3032103ecb24876e81293acca623d39dbc74ad23d2483e14ba2cbb86ac6d75eb5689d29ffffffff02c095a905000000001976a9140a6dd4fc6b19713621871f01fd9cfc37feb5026788ace0673500000000001976a9147c457cce7d24a467ff39d157d3e3c1371bf2b6c888ac00000000")
XCTAssertEqual(transaction.bitcoinData.hex, expect.hex)
XCTAssertEqual(transaction.txID, "430bafc24b6724028af4455ebfc320b12bec24ca850376910a8302e00246af96")
}
func testSignTransaction4() {
// Transaction in testnet3
// https://api.blockcypher.com/v1/btc/test3/txs/0189910c263c4d416d5c5c2cf70744f9f6bcd5feaf0b149b02e5d88afbe78992
// build input1
let prevTxID = "2eb9d00e2448aea9601df8f4326ee6d753e80c3d261e78795da7b20bb5d451f3"
let hash = Data(Data(hex: prevTxID).reversed())
let index: UInt32 = 1
let outpoint = BTCTransaction.OutPoint(transactionHash: hash, index: index)
let subScript = Data(hex: "76a9147c457cce7d24a467ff39d157d3e3c1371bf2b6c888ac")
let inputForSign = BTCTransaction.Input(outPoint: outpoint, signatureScript: subScript, sequence: UInt32.max)
// build input2
let prevTxID2 = "02e7c0a97dee2f31d4fe181c735fb32f8166664f7630c713d003f584cfafb490"
let hash2 = Data(Data(hex: prevTxID2).reversed())
let outpoint2 = BTCTransaction.OutPoint(transactionHash: hash2, index: 0)
let subScript2 = Data(hex: "76a9147c457cce7d24a467ff39d157d3e3c1371bf2b6c888ac")
let inputForSign2 = BTCTransaction.Input(outPoint: outpoint2, signatureScript: subScript2, sequence: UInt32.max)
// build output
let balance: Int64 = 68000000
let balance2: Int64 = 32500000
let amount: Int64 = 95000000
let fee: Int64 = 2000000
let toAddress = "mgU6dEQBFpwdSD46Qq2MoMw1tCBi3hEmvy" // https://testnet.coinfaucet.eu/en/
let toPubKeyHash = Base58.decode(toAddress).dropFirst().dropLast(4)
let privateKey = try! PrivateKey(wif: "cVX5NApUtWqrJneZK2PYsjqcbJvSZVU4Wh7CEF9CQP9Qwa2pCANV")
let fromPublicKey = privateKey.publicKey()
XCTAssertEqual(fromPublicKey.raw.hex, "03ecb24876e81293acca623d39dbc74ad23d2483e14ba2cbb86ac6d75eb5689d29")
let fromPubKeyHash = Crypto.sha256ripemd160(fromPublicKey.raw)
let lockingScript1 = Script.buildPublicKeyHashOut(pubKeyHash: toPubKeyHash)
let lockingScript2 = Script.buildPublicKeyHashOut(pubKeyHash: fromPubKeyHash)
XCTAssertEqual(lockingScript1.hex, "76a9140a6dd4fc6b19713621871f01fd9cfc37feb5026788ac")
XCTAssertEqual(lockingScript2.hex, "76a9147c457cce7d24a467ff39d157d3e3c1371bf2b6c888ac")
let sending = BTCTransaction.Output(value: amount, lockingScript: lockingScript1)
let payback = BTCTransaction.Output(value: balance + balance2 - amount - fee, lockingScript: lockingScript2)
// build signed BTCTransaction input1
let _tx = BTCTransaction(version: 1, inputs: [inputForSign], outputs: [sending, payback], lockTime: 0)
let hashType: SighashType = SighashType.BTC.SINGLE
let _txHash = Crypto.doubleSHA256(_tx.bitcoinData + UInt32(hashType).littleEndian)
XCTAssertEqual(_txHash.hex, "23bce5a777f3c90d73c5f0af2b03c9faccd08b37c3c6a982165814a714ff9265")
guard let signature: Data = try? Crypto.sign(_txHash, privateKey: privateKey) else {
XCTFail("failed to sign")
return
}
XCTAssertEqual(signature.hex, "3044022037533c68e544db72b0ad27e0514626408e9c4e447a61566a0ad2343ee02c3d4102206574f4bef4c27b64b3ba570bc9d95b9bd8b827f28d2151f314cc5310196f06d2")
// scriptSig: <sig> <pubKey>
var unlockingScript: Data = Data([UInt8(signature.count + 1)]) + signature + UInt8(hashType)
unlockingScript += UInt8(fromPublicKey.raw.count)
unlockingScript += fromPublicKey.raw
let input = BTCTransaction.Input(outPoint: outpoint, signatureScript: unlockingScript, sequence: UInt32.max)
// build signed BTCTransaction input2
let _tx2 = BTCTransaction(version: 1, inputs: [inputForSign2], outputs: [sending, payback], lockTime: 0)
let _txHash2 = Crypto.doubleSHA256(_tx2.bitcoinData + UInt32(hashType).littleEndian)
XCTAssertEqual(_txHash2.hex, "444c452e767c626f6fc1c1b940b27cf246f71a2f37ed4e39b5339e8c8f1ca5fc")
guard let signature2: Data = try? Crypto.sign(_txHash2, privateKey: privateKey) else {
XCTFail("failed to sign")
return
}
XCTAssertEqual(signature.hex, "3044022037533c68e544db72b0ad27e0514626408e9c4e447a61566a0ad2343ee02c3d4102206574f4bef4c27b64b3ba570bc9d95b9bd8b827f28d2151f314cc5310196f06d2")
// scriptSig: <sig> <pubKey>
var unlockingScript2: Data = Data([UInt8(signature2.count + 1)]) + signature2 + UInt8(hashType)
unlockingScript2 += UInt8(fromPublicKey.raw.count)
unlockingScript2 += fromPublicKey.raw
let input2 = BTCTransaction.Input(outPoint: outpoint2, signatureScript: unlockingScript2, sequence: UInt32.max)
// build BTCTransaction
let transaction = BTCTransaction(version: 1, inputs: [input, input2], outputs: [sending, payback], lockTime: 0)
let expect = Data(hex: "0100000002f351d4b50bb2a75d79781e263d0ce853d7e66e32f4f81d60a9ae48240ed0b92e010000006a473044022037533c68e544db72b0ad27e0514626408e9c4e447a61566a0ad2343ee02c3d4102206574f4bef4c27b64b3ba570bc9d95b9bd8b827f28d2151f314cc5310196f06d2032103ecb24876e81293acca623d39dbc74ad23d2483e14ba2cbb86ac6d75eb5689d29ffffffff90b4afcf84f503d013c730764f6666812fb35f731c18fed4312fee7da9c0e702000000006b483045022100a5a602528de5f741ab58fa62ae0d51a1813f36642172d986ef3342ad36cf6fc1022050beb570a28e5708844b98880c9d984919fa7de3efdef10d0c7fd97c787025a8032103ecb24876e81293acca623d39dbc74ad23d2483e14ba2cbb86ac6d75eb5689d29ffffffff02c095a905000000001976a9140a6dd4fc6b19713621871f01fd9cfc37feb5026788ace0673500000000001976a9147c457cce7d24a467ff39d157d3e3c1371bf2b6c888ac00000000")
XCTAssertEqual(transaction.bitcoinData.hex, expect.hex)
XCTAssertEqual(transaction.txID, "ca56271ffb2ada14f3624125cd3ba5bc14ab00b7d7cd334ba6f70edac3ff904b")
}
testSignTransaction3
and testSignTransaction4
both passed unit test.
I paste transaction.bitcoinData.hex
value to this page https://live.blockcypher.com/btc/pushtx/ Transaction Hex*
and select Bitcoin Testnet
, then click Broadcast Transaction
.
And both verified failed.
Both show Error validating transaction: Error running script for input 0 referencing 2eb9d00e2448aea9601df8f4326ee6d753e80c3d261e78795da7b20bb5d451f3 at 1: Script was NOT verified successfully..
I don't know why. It cost me a lot time to try.
Can you help me?
After solved this problem, I will make a PR if you pleasure.
Thanks a lot.
question