Closed oguzsoft closed 3 years ago
The above information alone does not tell us where the error occurred. Can you provide a stack trace or some other way to see the error? Also, the payload of the transaction where the error occurred.
Firstly I'm doing a blockchain scan. If there is an address belonging to me on the 'to' side or 'change' side of a transaction, I save the details of this transaction in the database as spent=false.
Step of construct transaction When a send request comes while a creating inputs, I sort the amount values of hot_wallet's unspent transactions in ascending order and ı loop until it exceeds the amount of sending requests. In here, If you have a suggestion I would like to know your suggestion. While a creating outputs, ı use address and amount of transaction_request param.
Finally If transaction is created successfuly and If transaction broadcasted is success, ı update as spent=true ı used transaction(should_be_spent)
Descriptions
A example of transaction request param:
[
{ 'address' => 'my7q6HZfQnnuFXU9rdLzzatpopbx69K5KC',
'amount' => '0.00002',
},
{ 'address' => 'mjFEuoARzZRV9PAfJhr3ELRYE7xMtNwt8j',
'amount' => '0.00001',
}
]
Construct tx method
def construct_transaction(transaction_requests)
total_amount_of_all_withdrawals = transaction_requests.map { |w| (w['amount'].to_d * 10**8)}.sum.to_i
fee = 1000
total = total_amount_of_all_withdrawals + fee
unspent_transactions = get_utxos(hot_wallet.address, hot_wallet.construct_key)
sorted_utxos = unspent_transactions.sort_by { |i| (i[:value].to_d * 10**8).to_i }
should_be_spent = []
input_amount = 0
new_tx = build_tx do |t|
sorted_utxos.each do |input|
t.input do |i|
i.prev_out input[:tx]
i.prev_out_index input[:index]
i.signature_key ::Bitcoin::Key.new(input[:key_as_hex])
end
input_amount += input[:value]
should_be_spent << input[:tx].hash
break if input_amount >= total
end
transaction_requests.each do |tx_req|
t.output do |o|
o.value (tx_req['amount'].to_d * 10**8).to_i
o.script { |s| s.recipient tx_req['address'] }
end
end
change = input_amount - total
if change > 0
t.output do |o|
o.value change
o.script { |s| s.recipient hot_wallet.address }
end
end
end
[new_tx.hash, new_tx.to_payload.bth, should_be_spent]
end
As I said above, sometimes it works properly. But sometimes ı get an error: 'Undefined bytesize method' for nil:NilClass. I think probably, while creating output, o.script is nil... But this is only guess. If there is any place you cannot understand, ı would be happy to answer.
The bytesize
calculation is used by many pieces of code in the library, and an error is occurring somewhere in one of them. To determine where the error is occurring, you need a stack trace with the line number of the error.
NoMethodError: undefined method `bytesize' for nil:NilClass
from /Users/oguz/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/bitcoin-ruby-0.0.20/lib/bitcoin/protocol/txout.rb:90:in `pk_script='
[7] pry(main)> wtf?
Exception: NoMethodError: undefined method `bytesize' for nil:NilClass
--
0: /Users/oguz/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/bitcoin-ruby-0.0.20/lib/bitcoin/protocol/txout.rb:90:in `pk_script='
1: /Users/oguz/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/bitcoin-ruby-0.0.20/lib/bitcoin/builder.rb:549:in `script'
2: /Users/oguz/Workspace/Locale/foo/foo_project/app/services/hot_wallet_raw_transaction_maker_service/bitcoin.rb:88:in `block (3 levels) in construct_transaction'
3: /Users/oguz/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/bitcoin-ruby-0.0.20/lib/bitcoin/builder.rb:167:in `output'
4: /Users/oguz/Workspace/Locale/foo/foo_project/app/services/hot_wallet_raw_transaction_maker_service/bitcoin.rb:86:in `block (2 levels) in construct_transaction'
5: /Users/oguz/Workspace/Locale/foo/foo_project/app/services/hot_wallet_raw_transaction_maker_service/bitcoin.rb:85:in `each'
6: /Users/oguz/Workspace/Locale/foo/foo_project/app/services/hot_wallet_raw_transaction_maker_service/bitcoin.rb:85:in `block in construct_transaction'
7: /Users/oguz/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/bitcoin-ruby-0.0.20/lib/bitcoin/builder.rb:20:in `build_tx'
8: /Users/oguz/Workspace/Locale/foo/foo_project/app/services/hot_wallet_raw_transaction_maker_service/bitcoin.rb:73:in `construct_transaction'
9: /Users/oguz/Workspace/Locale/foo/foo_project/app/services/hot_wallet_raw_transaction_maker_service/bitcoin.rb:21:in `call'
[8] pry(main)>
# line 2: /Users/oguz/Workspace/Locale/foo/foo_project/app/services/hot_wallet_raw_transaction_maker_service/bitcoin.rb:88:in `block (3 levels) in construct_transaction'
85: transaction_requests.each do |tx_req|
86: t.output do |o|
87: o.value (tx_req['amount'].to_d * 10**8).to_i
88: o.script { |s| s.recipient tx_req['address'] }
89: end
90: end
# line 8: /Users/oguz/Workspace/Locale/foo/foo_project/app/services/hot_wallet_raw_transaction_maker_service/bitcoin.rb:73:in `construct_transaction'
73: new_tx = build_tx do |t|
sorted_utxos.each do |input|
t.input do |i|
i.prev_out input[:tx]
i.prev_out_index input[:index]
.
.
.
construct_transaction method is called from call method.
# line 9: /Users/oguz/Workspace/Locale/foo/foo_project/app/services/hot_wallet_raw_transaction_maker_service/bitcoin.rb:21:in `call'
According to the stack trace
88: o.script { |s| s.recipient tx_req['address'] }
There seems to be an error in Script.to_address_script
that is called inside above code. In other words, there are cases where Script.to_address_script(tx_req ['address'])
returns nil.
You should check the data in tx_req ['address']
that Script.to_address_script
cannot interpret.
I don't know how to do it more correctly. What would you think about this? I really couldn't understand this error.
[84, 93] in /Users/oguz/Workspace/Locale/foo/foo_project/app/services/hot_wallet_raw_transaction_maker_service/bitcoin.rb
84:
85: transaction_requests.each do |tx_req|
86: t.output do |o|
87: o.value (tx_req['amount'].to_d * 10**8).to_i
88: byebug
=> 89: o.script { |s| s.recipient tx_req['address'] }
90: end
91: end
92:
93:
(byebug) tx_req
{"address"=>"my7q6HZfQnnuFXU9rdLzzatpopbx69K5KC", "amount"=>"0.00002"}
(byebug) tx_req['address']
"my7q6HZfQnnuFXU9rdLzzatpopbx69K5KC"
(byebug) tx_req['amount']
"0.00002"
(byebug) o.value (tx_req['amount'].to_d * 10**8).to_i
2000
(byebug) o.script { |s| s.recipient tx_req['address'] }
*** NoMethodError Exception: undefined method `bytesize' for nil:NilClass
nil
(byebug)
hmm, I wrote code snippet:
require 'bigdecimal/util'
Bitcoin.network = :testnet
include Bitcoin::Builder
tx_req = {}
tx_req['address'] = 'my7q6HZfQnnuFXU9rdLzzatpopbx69K5KC'
tx_req['amount'] = "0.00002"
new_tx = build_tx do |t|
t.output do |o|
o.value (tx_req['amount'].to_d * 10**8).to_i
o.script { |s| s.recipient tx_req['address'] }
end
end
it' work fine. Is the network testnet using Bitcoin.network = :testnet
?
If you use other network, code will raise NoMethodError Exception: undefined method bytesize for nil:NilClass
.
Output Bitcoin.network_name
when executing the code, you can see the applied network.
Actually I was configuring Bitcoin.network in another file. In now I moved this to in construct_transaction method. It's work fine. I will try many construct transactions and ı will write the results... Thank you so much for your help.
Its work fine... Thank you @azuchi
NoMethodError (undefined method `bytesize' for nil:NilClass)
Has anyone encountered this error before when create a new transaction? Sometimes when creating output, sometimes when creating input. I don't know why? Also, sometimes is working :). I will understand if it never works, ı have an error. Note: Everytime, sender address has a enough coin and recipient address is valid address.