Ich bin neu im Programmieren und kenne nur Swift, obj-C ist mir noch fremd. Ich habe eine funktionierende Brieftasche, aber im Moment verlasse ich mich auf die BlockCypher-API, um eine Transaktion zu erstellen, die ich NICHT machen möchte. Kann mir bitte jemand sagen, was ich im folgenden Code-Snippet falsch mache. Ich erstelle eine Rohtransaktion, aber ich bekomme eine seltsame Antwort, wenn ich sie decodiere, wo die Adressarrays leer oder null sind. Irgendetwas stimmt nicht, wenn jemand irgendwelche Erfahrungen hat, würde ich es sehr schätzen, denn das macht mich verrückt.
import UIKit
Klasse BuildTransactionViewController: UIViewController, BTCTransactionBuilderDataSource {
var addressToSpendFrom = "n1QQYAHbw3q6UjWN6Q4d9oqa6u5iUDnPHT"
var privateKeyToSign = "cNeZkP1QPQ37C4rLvoQ8xZ5eujcjsYHZMj8CLfPPohYPvfKhzHWu"
var receiverAddress = "n1v9HH9Abs36fYf8KbwnFUfzR4prLBXhtW"
var inputData = [NSDictionary]()
var scriptArray = [String]()
var transaction = BTCTransaction()
override func viewDidLoad() {
super.viewDidLoad()
getUTXOforAddress(address: addressToSpendFrom)
}
func getUTXOforAddress(address: String) {
var url:NSURL!
url = NSURL(string: "https://api.blockcypher.com/v1/btc/test3/addrs/\(address)?unspentOnly=true")
let task = URLSession.shared.dataTask(with: url! as URL) { (data, response, error) -> Void in
do {
if error != nil {
print(error as Any)
DispatchQueue.main.async {
displayAlert(viewController: self, title: "Error", message: "Please check your interent connection.")
}
} else {
if let urlContent = data {
do {
let jsonUTXOResult = try JSONSerialization.jsonObject(with: urlContent, options: JSONSerialization.ReadingOptions.mutableLeaves) as! NSDictionary
print("json = \(jsonUTXOResult)")
if let utxoCheck = jsonUTXOResult["txrefs"] as? NSArray {
self.inputData = utxoCheck as! [NSDictionary]
print("utxoCheck = \(utxoCheck)")
for item in self.inputData {
let transactionHash = (item)["tx_hash"] as! String
let value = (item)["value"] as! Int
var url:NSURL!
url = NSURL(string: "https://api.blockcypher.com/v1/btc/test3/txs/\(transactionHash)")
let task = URLSession.shared.dataTask(with: url! as URL) { (data, response, error) -> Void in
do {
if error != nil {
print(error as Any)
DispatchQueue.main.async {
displayAlert(viewController: self, title: "Error", message: "Please check your interent connection.")
}
} else {
if let urlContent = data {
do {
let txHashResult = try JSONSerialization.jsonObject(with: urlContent, options: JSONSerialization.ReadingOptions.mutableLeaves) as! NSDictionary
print("txHashResult = \(txHashResult)")
if let outputsCheck = txHashResult["outputs"] as? NSArray {
print("outputs = \(outputsCheck)")
for output in outputsCheck {
if let valueCheck = (output as! NSDictionary)["value"] as? Int {
if valueCheck == value {
let script = (output as! NSDictionary)["script"] as! String
self.scriptArray.append(script)
print("script = \(script)")
}
}
}
print("inputData = \(self.inputData)")
print("scriptArray = \(self.scriptArray)")
self.callBTCTransaction()
}
} catch {
print("JSon processing failed")
DispatchQueue.main.async {
displayAlert(viewController: self, title: "Error", message: "Please try again.")
}
}
}
}
}
}
task.resume()
}
}
} catch {
print("JSon processing failed")
DispatchQueue.main.async {
displayAlert(viewController: self, title: "Error", message: "Please try again.")
}
}
}
}
}
}
task.resume()
}
func callBTCTransaction() {
let address = BTCAddress(string: self.receiverAddress)
let newTransaction = BTCTransactionBuilder()
newTransaction.dataSource = self
newTransaction.shouldSign = true
newTransaction.changeAddress = BTCAddress(string: self.addressToSpendFrom)
newTransaction.outputs = [BTCTransactionOutput(value: BTCAmount(1000), address: address)]
newTransaction.feeRate = BTCAmount(2000)
var result:BTCTransactionBuilderResult? = nil
do {
result = try newTransaction.buildTransaction()
print("transactionRaw = \(String(describing: result?.transaction.hex))")
} catch {
print("error = \(error as Any)")
}
}
func transactionBuilder(_ txbuilder: BTCTransactionBuilder!, keyForUnspentOutput txout: BTCTransactionOutput!) -> BTCKey! {
print("transactionBuilder")
let key = BTCKey.init(wif: self.privateKeyToSign)
key?.isPublicKeyCompressed = true
return key
}
func unspentOutputs(for txbuilder: BTCTransactionBuilder!) -> NSEnumerator! {
let outputs = NSMutableArray()
for (index, item) in inputData.enumerated() {
let txout = BTCTransactionOutput()
txout.value = BTCAmount((item).value(forKey: "value") as! Int64)
txout.script = BTCScript.init(hex: self.scriptArray[index])
txout.index = UInt32((item).value(forKey: "tx_output_n") as! Int)
txout.confirmations = UInt((item).value(forKey: "confirmations") as! Int)
let transactionHash = (item)["tx_hash"] as! String
txout.transactionHash = transactionHash.data(using: .utf8)
outputs.add(txout)
}
print("outputs = \(outputs)")
return outputs.objectEnumerator()
}
}
Kann ich wegen schlechter Reputation nicht kommentieren. Sehen Sie sich diesen Link an: https://github.com/oleganza/CoreBitcoin/blob/master/CoreBitcoinTestsOSX/BTCTransactionTests.swift
Im Grunde erstellen sie einen TX wie diesen:
let tx = BTCTransaction()
var spentCoins = BTCAmount(0)
// Add all outputs as inputs
for txout in txouts {
let txin = BTCTransactionInput()
txin.previousHash = txout.transactionHash
txin.previousIndex = txout.index
tx.addInput(txin)
print("txhash: http://blockchain.info/rawtx/\(BTCHexFromData(txout.transactionHash))")
print("txhash: http://blockchain.info/rawtx/\(BTCHexFromData(BTCReversedData(txout.transactionHash))) (reversed)")
spentCoins += txout.value
}
print(String(format: "Total satoshis to spend: %lld", spentCoins))
print(String(format: "Total satoshis to destination: %lld", amount))
print(String(format: "Total satoshis to fee: %lld", fee))
print(String(format: "Total satoshis to change: %lld", spentCoins - (amount + fee)))
// Add required outputs - payment and change
let paymentOutput = BTCTransactionOutput(value: amount, address: destinationAddress)
let changeOutput = BTCTransactionOutput(value: (spentCoins - (amount + fee)), address: changeAddress)
// Idea: deterministically-randomly choose which output goes first to improve privacy.
tx.addOutput(paymentOutput)
tx.addOutput(changeOutput)
for i in 0 ..< txouts.count {
// Normally, we have to find proper keys to sign this txin, but in this
// example we already know that we use a single private key.
let txout = txouts[i] // output from a previous tx which is referenced by this txin.
let txin = tx.inputs[i] as! BTCTransactionInput
let sigScript = BTCScript()
let d1 = tx.data
let hashType = BTCSignatureHashType.SIGHASH_ALL
let getHash: NSData?
do {
getHash = try tx.signatureHashForScript(txout.script, inputIndex: UInt32(i), hashType: hashType)
} catch {
errorOut = error
getHash = nil
}
let d2 = tx.data
XCTAssertEqual(d1, d2, "Transaction must not change within signatureHashForScript!")
// 134675e153a5df1b8e0e0f0c45db0822f8f681a2eb83a0f3492ea8f220d4d3e4
guard let hash = getHash else { return (nil, errorOut) }
print(String(format: "Hash for input %d: \(BTCHexFromData(hash))", i))
let signatureForScript = key.signatureForHash(hash, hashType: hashType)
sigScript.appendData(signatureForScript)
sigScript.appendData(key.publicKey)
let sig = signatureForScript.subdataWithRange(NSRange(location: 0, length: signatureForScript.length - 1)) // trim hashtype byte to check the signature.
XCTAssertTrue(key.isValidSignature(sig, hash: hash), "Signature must be valid")
txin.signatureScript = sigScript
}
// Validate the signatures before returning for extra measure.
do {
let sm = BTCScriptMachine(transaction: tx, inputIndex: 0)
do {
try sm.verifyWithOutputScript((txouts.first as BTCTransactionOutput!).script.copy() as! BTCScript)
} catch {
print("Error: \(error)")
XCTFail("should verify first output")
}
}
In meinem Fall stelle ich tx wieder her, das auf dem JS-Backend erstellt wurde, und signiere es nur. Ich werde mein Codebeispiel später posten.
Fontaine