Class: Bitcoin::Builder::TxBuilder

Inherits:
Object
  • Object
show all
Defined in:
lib/bitcoin/builder.rb

Overview

DSL to create Bitcoin::Protocol::Tx used by Builder#build_tx.

tx = tx do |t|
  t.input do |i|
    i.prev_out prev_tx  # previous transaction
    i.prev_out_index 0  # index of previous output
    i.signature_key key # Bitcoin::Key used to sign the input
  end
  t.output do |o|
    o.value 12345 # 0.00012345 BTC
    o.script {|s| s.type :address; s.recipient key.addr }
  end
end

signs every input that has a signature key. if the signature key is not specified, the input will include the #sig_hash that needs to be signed.

Instance Method Summary collapse

Constructor Details

#initializeTxBuilder

Returns a new instance of TxBuilder.



134
135
136
137
138
# File 'lib/bitcoin/builder.rb', line 134

def initialize
  @tx = P::Tx.new(nil)
  @tx.ver, @tx.lock_time = 1, 0
  @ins, @outs = [], []
end

Instance Method Details

#input {|c| ... } ⇒ Object

add an input to the transaction (see TxInBuilder).

Yields:

  • (c)


151
152
153
154
155
# File 'lib/bitcoin/builder.rb', line 151

def input
  c = TxInBuilder.new
  yield c
  @ins << c
end

#lock_time(n) ⇒ Object

specify tx lock_time. this is usually not necessary. defaults to 0.



146
147
148
# File 'lib/bitcoin/builder.rb', line 146

def lock_time n
  @tx.lock_time = n
end

#output {|c| ... } ⇒ Object

add an output to the transaction (see TxOutBuilder).

Yields:

  • (c)


158
159
160
161
162
# File 'lib/bitcoin/builder.rb', line 158

def output
  c = TxOutBuilder.new
  yield c
  @outs << c
end

#txObject

create the transaction according to values specified via DSL. sign each input that has a signature key specified. if there is no key, store the sig_hash in the input, so it can easily be signed later.



168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# File 'lib/bitcoin/builder.rb', line 168

def tx
  @ins.each {|i| @tx.add_in(i.txin) }
  @outs.each {|o| @tx.add_out(o.txout) }
  @ins.each_with_index do |inc, i|
    if @tx.in[i].coinbase?
      script_sig = [inc.coinbase_data].pack("H*")
      @tx.in[i].script_sig_length = script_sig.bytesize
      @tx.in[i].script_sig = script_sig
      next
    end
    prev_tx = inc.instance_variable_get(:@prev_out)
    @sig_hash = @tx.signature_hash_for_input(i, prev_tx)
    if inc.key && inc.key.priv
      sig = inc.key.sign(@sig_hash)
      script_sig = Script.to_signature_pubkey_script(sig, [inc.key.pub].pack("H*"))
      @tx.in[i].script_sig_length = script_sig.bytesize
      @tx.in[i].script_sig = script_sig
      raise "Signature error"  unless @tx.verify_input_signature(i, prev_tx)
    else
      @tx.in[i].script_sig_length = 0
      @tx.in[i].script_sig = ""
      @tx.in[i].sig_hash = @sig_hash
      @tx.in[i].sig_address = Script.new(prev_tx.out[@tx.in[i].prev_out_index].pk_script).get_address
    end
  end
  data = @tx.in.map {|i| [i.sig_hash, i.sig_address] }
  tx = P::Tx.new(@tx.to_payload)
  data.each.with_index {|d, i| i = tx.in[i]; i.sig_hash = d[0]; i.sig_address = d[1] }
  raise "Payload Error"  unless tx.to_payload == @tx.to_payload
  tx
end

#version(n) ⇒ Object

specify tx version. this is usually not necessary. defaults to 1.



141
142
143
# File 'lib/bitcoin/builder.rb', line 141

def version n
  @tx.ver = n
end