Closed hanshaueter closed 6 years ago
maybe regenerate_public_key
returns uncompressed pubkey, so pubkey hash check failed.
Thank you very much for your kind support which I have tried to implement. I tried to generate a Bitcoin Cash transaction with a compressed key (or at least that's what I think I was using) and the transaction still doesn't go through. It seems that the binary transaction is 2bits too short.
I was using the Bitcoin.open_key method this time.
Please find below the full details of the code:
`prev_tx_output_index = 1
prev_tx_json = HTTParty.get('https://blockdozer.com/insight-api/rawtx/4cda2581911ab3d7ee29b22dbd7701f278d33cdcd8535d911ab621a96171af24')["rawtx"].to_s
prev_tx_test =[prev_tx_json].pack("H*")
prev_tx = Bitcoin::Protocol::Tx.new(prev_tx_test)
value = prev_tx.outputs[prev_tx_output_index].value - 1000
tx = Bitcoin::Protocol::Tx.new tx.add_in Bitcoin::Protocol::TxIn.new(prev_tx.binary_hash, prev_tx_output_index, 0) tx.add_out Bitcoin::Protocol::TxOut.value_to_address(value, "1BLe5eavCg6Jxkt21edCxgPKmY3Ks8hTGL")
key = Bitcoin.open_key("c35ec65e83188458487e127db7a554aa5e3567ff0e131c7e5a94a5a1c7f54a18")
sig = Bitcoin.sign_data(key, tx.signature_hash_for_input(0, prev_tx.out[1].pk_script, 0, prev_tx.out[1], 0)) tx.in[0].script_sig = Bitcoin::Script.to_signature_pubkey_script(sig, [key.public_key_hex].pack("H*"), 0) tx = Bitcoin::Protocol::Tx.new( tx.to_payload )
p tx.verify_input_signature(0, prev_tx) == true
puts tx.to_payload.unpack("H*")[0]
Any support would be highly appreciated.
use the https://github.com/lian/bitcoin-ruby#keysaddresses Bitcoin::Key object instead. gets rid of compressed vs uncompressed. also Key#initialize(privkey = nil, pubkey = nil, opts={compressed: true})
can define if the used key is compressed or uncompressed
Thank you for your inputs! Which is very helpful! Now I managed to get the signature test tx.verify_input_signature(0, prev_tx)
on true.
I changed the following elements:
key = Bitcoin::Key.new("c35ec65e83188458487e127db7a554aa5e3567ff0e131c7e5a94a5a1c7f54a18", pubkey = nil, opts={compressed: true})
sig = Bitcoin.sign_data(key.key, tx.signature_hash_for_input(0, prev_tx.out[1].pk_script, 0, prev_tx.out[1], 0)) tx.in[0].script_sig = Bitcoin::Script.to_signature_pubkey_script(sig, [key.pub].pack("H*"), 0)
However, when I go on https://blockdozer.com to send the transaction, I still get the "An error occured: 16: mandatory-script-verify-flag-failed (Signature hash type missing or not understood). Code:-26" Do you have an idea why this happens? It seems there is still a problem with the signature. Thank you very much for inputs!
signature_hash_for_input(input_idx, subscript, hash_type=nil, prev_out_value=nil, fork_id=nil)
you set fork_id to 0 in your code so it won't run signature_hash_for_input_bip143
internally, set it to 64 instead. also your hash_type should be hash_type = Bitcoin::Script::SIGHASH_TYPE[:all] | Bitcoin::Script::SIGHASH_TYPE[:forkid]
so replace those 0s with that value instead too
Thank you very much. I have changed the two lines as follows:
sig = Bitcoin.sign_data(key.key, tx.signature_hash_for_input(0, prev_tx.out[1].pk_script, 1, prev_tx.out[1], 64)) tx.in[0].script_sig = Bitcoin::Script.to_signature_pubkey_script(sig, [key.pub].pack("H*"), 1)
I set the hash_type to 1 and fork_id to 64. I still get the same error ("An error occured:
16: mandatory-script-verify-flag-failed (Signature hash type missing or not understood). Code:-26") when submitting on blockdozer.com.
I'm sorry I might have misunderstood your comment, but I can't get it running. If I set both hash_type and fork_id to 64:
sig = Bitcoin.sign_data(key.key, tx.signature_hash_for_input(0, prev_tx.out[1].pk_script, 64, prev_tx.out[1], 64)) tx.in[0].script_sig = Bitcoin::Script.to_signature_pubkey_script(sig, [key.pub].pack("H*"), 64)
it get an error message in the Bash console
"tx.rb:191:in `signature_hash_for_input': fork_id must be 0"
Thank you very much for help. It's highly appreciated.
i said to set hash_type to :all | :forkid
which is 1 | 64
which is the value 65
just set and use those variables..
hash_type = Bitcoin::Script::SIGHASH_TYPE[:all] | Bitcoin::Script::SIGHASH_TYPE[:forkid]
forkid = Bitcoin::Script::SIGHASH_TYPE[:forkid]
Your the best! I was able to successfully broadcast a transaction using your method! Thank you 1000 times for your inputs. I changed it as follows: `sig = Bitcoin.sign_data(key.key, tx.signature_hash_for_input(0, prev_tx.out[1].pk_script, 65, prev_tx.out[1].value, 0))
tx.in[0].script_sig = Bitcoin::Script.to_signature_pubkey_script(sig, [key.pub].pack("H*"), 65)`
I guess the only question I now still have is why does the test
p tx.verify_input_signature(0, prev_tx)
change to false?
gotta pass the forkid too p tx.verify_input_signature(0, prev_tx, Time.now.to_i, { fork_id: Bitcoin::Script::SIGHASH_TYPE[:forkid] })
@lian https://github.com/lian/bitcoin-ruby/blob/master/lib/bitcoin/protocol/tx.rb#L191
As your said set fork_id to 0 in your code so it won't run signature_hash_for_input_bip143 internally, set it to 64 instead.
i wonder how can we pass above code if fork_id = 64.
When I try to send the transaction via https://blockdozer.com/tx/send I receive the following error message: "16: mandatory-script-verify-flag-failed (Script failed an OP_EQUALVERIFY operation). Code:-26". I used hashtype 0 and fork_id 64 as I understand that's what needs to be changed from bitcoin to bitcoin cash. => sighash = new_tx.signature_hash_for_input(0, prev_tx, 0, prev_tx.out, 64) I guess I'm missing another relevant adjustment. Please find below how I built the transaction. Any input would be highly appreciated. new_tx = build_tx do |t|
t.input do |i| i.prev_out prev_tx.hash i.prev_out_index prev_out_index i.signature_key key end
t.output do |o| o.value 9000 o.script {|s| s.recipient "1BLe5eavCg6Jxkt21edCxgPKmY3Ks8hTGL" } end
end sighash = new_tx.signature_hash_for_input(0, prev_tx, 0, prev_tx.out, 64) sig = Bitcoin.sign_data(key.key, sighash)
public_key = regenerate_public_key(key.key.private_key_hex) new_tx.in[0].script_sig = Bitcoin::Script.to_signature_pubkey_script(sig, [public_key].pack("H*"), 0)
new_tx = Bitcoin::Protocol::Tx.new( new_tx.to_payload ) p new_tx.to_payload.unpack("H*")[0]