Class: BTC::AssetTransaction

Inherits:
Object
  • Object
show all
Defined in:
lib/btcruby/open_assets/asset_transaction.rb

Overview

Wrapper around Transaction that stores info about assets on inputs and outputs.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(transaction: nil, data: nil) ⇒ AssetTransaction

Returns a new instance of AssetTransaction.

Raises:

  • (ArgumentError)


27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/btcruby/open_assets/asset_transaction.rb', line 27

def initialize(transaction: nil, data: nil)
  if data && !transaction
    txdata, len = WireFormat.read_string(data: data, offset: 0)
    raise ArgumentError, "Invalid data: tx data" if !txdata
    transaction = Transaction.new(data: txdata)
    data = data[len..-1]
  end
  raise ArgumentError, "Missing transaction" if !transaction
  raise FormatError, "Transaction does not contain an AssetMarker" if !transaction.open_assets_transaction?
  raise FormatError, "Coinbase transactions cannot be AssetTransactions" if transaction.coinbase?
  raise FormatError, "Transactions with no inputs cannot be AssetTransactions" if transaction.inputs.size == 0

  @transaction = transaction

  # Extract the first marker output
  marker_output = transaction.outputs.find{|txout| txout.script.open_assets_marker? }
  @marker = AssetMarker.new(output: marker_output) # raises if marker is malformed

  # Create unverified inputs.
  @inputs = transaction.inputs.map do |txin|
    AssetTransactionInput.new(transaction_input: txin)
  end

  # Create unverified outputs for all outputs.
  @outputs = transaction.outputs.inject([]) do |array, txout|
    # note: other outputs looking like markers are allowed, so we check for the first one only.
    aout = AssetTransactionOutput.new(transaction_output: txout)
    if txout == marker_output
      aout.marker = true
      aout.verified = true
    else
      if (txout.index < marker_output.index)
        aout.issue = true
      else
        aout.transfer = true
      end
    end
    array << aout
  end

  # Check that the marker contains not more quantities than outputs available.
  # Marker output does not count and is not included in quantities list.
  if @marker.quantities.size > (@outputs.size - 1)
    raise FormatError, "OpenAssets marker specifies more quantities than colorable outputs available: #{@marker.quantities.size} > #{@outputs.size-1}."
  end

  # Fill in assets amounts for outputs (but keep them unverified).
  # Excessive outputs receive `nil` amount.
  @outputs.find_all{|o|!o.marker?}.each_with_index do |aout, i|
    aout.value = @marker.quantities[i]
  end

  # contains only color info about ins/outs
  if data
    offset = 0
    @inputs.each do |ain|
      offset = ain.parse_assets_data(data, offset: offset)
    end
    @outputs.each do |aout|
      if !aout.marker?
        offset = aout.parse_assets_data(data, offset: offset)
      end
    end
  end
end

Instance Attribute Details

#inputsObject

List of AssetTransactionInput instances.



12
13
14
# File 'lib/btcruby/open_assets/asset_transaction.rb', line 12

def inputs
  @inputs
end

#markerObject

AssetMarker instance describing the transaction



18
19
20
# File 'lib/btcruby/open_assets/asset_transaction.rb', line 18

def marker
  @marker
end

#metadataObject (readonly)

Metadata stored in AssetMarker



21
22
23
# File 'lib/btcruby/open_assets/asset_transaction.rb', line 21

def 
  
end

#outputsObject

List of AssetTransactionOutput instances.



15
16
17
# File 'lib/btcruby/open_assets/asset_transaction.rb', line 15

def outputs
  @outputs
end

#transactionObject

Raw BTC::Transaction containing asset transfer



9
10
11
# File 'lib/btcruby/open_assets/asset_transaction.rb', line 9

def transaction
  @transaction
end

#transaction_hashObject (readonly)

Identifier of the underlying Bitcoin transaction.



24
25
26
# File 'lib/btcruby/open_assets/asset_transaction.rb', line 24

def transaction_hash
  @transaction_hash
end

#transaction_idObject (readonly)

Returns the value of attribute transaction_id.



25
26
27
# File 'lib/btcruby/open_assets/asset_transaction.rb', line 25

def transaction_id
  @transaction_id
end

Instance Method Details

#dataObject

Serialized tx will have:

  • raw tx data
  • array of input colors (verified yes/no, asset id, units)
  • array of output colors (verified yes/no, asset id, units) - do not contain marker output


97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/btcruby/open_assets/asset_transaction.rb', line 97

def data
  data = "".b
  txdata = @transaction.data
  data << WireFormat.encode_string(txdata)
  @inputs.each do |ain|
    data << ain.assets_data
  end
  @outputs.each do |aout|
    if !aout.marker?
      data << aout.assets_data
    end
  end
  data
end

#dupObject



154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/btcruby/open_assets/asset_transaction.rb', line 154

def dup
  atx = AssetTransaction.new(transaction: self.transaction.dup)
  self.inputs.each_with_index do |ain, i|
    ain2 = atx.inputs[i]
    ain2.asset_id = ain.asset_id
    ain2.value = ain.value
    ain2.verified = ain.verified
  end
  self.outputs.each_with_index do |aout, i|
    aout2 = atx.outputs[i]
    aout2.asset_id = aout.asset_id
    aout2.value = aout.value
    aout2.verified = aout.verified
    aout2.kind = aout.kind
  end
end

#inputs_verified?Boolean

Returns:

  • (Boolean)


138
139
140
# File 'lib/btcruby/open_assets/asset_transaction.rb', line 138

def inputs_verified?
  @inputs.all?{|i|i.verified?}
end

#inspectObject



171
172
173
174
175
176
# File 'lib/btcruby/open_assets/asset_transaction.rb', line 171

def inspect
  issues = issue_outputs.map{|out| out.value.inspect }.join(",")
  ins = inputs.map{|inp| inp.value.inspect }.join(",")
  outs = transfer_outputs.map{|out| out.value.inspect }.join(",")
  %{#<#{self.class}:#{self.transaction_id[0,8]} issues [#{issues}] transfers [#{ins}] => [#{outs}]>}
end

#issue_outputsObject



124
125
126
# File 'lib/btcruby/open_assets/asset_transaction.rb', line 124

def issue_outputs
  @outputs.find_all{|o| o.issue? }
end

#output_at_raw_index(i) ⇒ Object

deprecated



146
147
148
149
150
151
152
# File 'lib/btcruby/open_assets/asset_transaction.rb', line 146

def output_at_raw_index(i) # deprecated
  @outputs[i]
  # @outputs.find do |out|
  #   raise ArgumentError, "Underlying BTC::TransactionOutput instance are expected to have `index` attribute." if !out.index
  #   out.index == i
  # end
end

#outputs_verified?Boolean

Returns:

  • (Boolean)


142
143
144
# File 'lib/btcruby/open_assets/asset_transaction.rb', line 142

def outputs_verified?
  @outputs.all?{|o|o.verified?}
end

#transfer_outputsObject



128
129
130
# File 'lib/btcruby/open_assets/asset_transaction.rb', line 128

def transfer_outputs
  @outputs.find_all{|o| o.transfer? }
end

#verified?Boolean

AssetTransaction is considered verified when all outputs are verified. Inputs may remain unverified when their assets are destroyed.

Returns:

  • (Boolean)


134
135
136
# File 'lib/btcruby/open_assets/asset_transaction.rb', line 134

def verified?
  outputs_verified?
end