counterparty_ruby 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1f5207b55688ced904bffa8b0c7e131bdbefeb63
4
+ data.tar.gz: da952475875e8dfebf067fed4881496ebd60e029
5
+ SHA512:
6
+ metadata.gz: b03863b18593a84e2c2d80c47d9adbf86c41f0cbac07ccb3fb3e826f2b68b8fe33cc44cdbec170fa477bb4494e4375e960670314fa553b03b33e2dd0a6c33aa3
7
+ data.tar.gz: 4063562be01b04a5353cadbb3bbafbfa80555b7ff284810404d221ae100cf08884f46915ee6eeb41fa8583c8a7d5536787087e9fc2eafd368020dfc1433073f6
@@ -1,23 +1,24 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- counterparty_ruby (1.1.0)
4
+ counterparty_ruby (1.2.0)
5
5
  bitcoin-ruby
6
6
  ffi
7
7
  rest-client
8
+ ruby-rc4
8
9
 
9
10
  GEM
10
11
  remote: https://rubygems.org/
11
12
  specs:
12
- bitcoin-ruby (0.0.6)
13
+ bitcoin-ruby (0.0.7)
13
14
  diff-lcs (1.2.5)
14
- domain_name (0.5.23)
15
+ domain_name (0.5.24)
15
16
  unf (>= 0.0.5, < 1.0.0)
16
17
  ffi (1.9.8)
17
18
  http-cookie (1.0.2)
18
19
  domain_name (~> 0.5)
19
20
  json (1.8.1)
20
- mime-types (2.4.3)
21
+ mime-types (2.6.1)
21
22
  netrc (0.10.3)
22
23
  rake (10.3.2)
23
24
  rdoc (4.2.0)
@@ -41,9 +42,10 @@ GEM
41
42
  rspec-mocks (3.1.3)
42
43
  rspec-support (~> 3.1.0)
43
44
  rspec-support (3.1.2)
45
+ ruby-rc4 (0.1.5)
44
46
  unf (0.1.4)
45
47
  unf_ext
46
- unf_ext (0.0.6)
48
+ unf_ext (0.0.7.1)
47
49
 
48
50
  PLATFORMS
49
51
  ruby
data/README.md CHANGED
@@ -26,6 +26,11 @@ setting everything up.
26
26
  ![Party On Wayne](http://data.whicdn.com/images/24796384/tumblr_m0ng6rBeWT1qhd0xso1_500_large.jpg)
27
27
 
28
28
  ## Changelog
29
+ _Version 1.2_
30
+ * Minor refactoring
31
+ * Added an extensive suite of tests for transaction encoding and decoding
32
+ * Implemented a counterparty transaction TxEncode/TxDecode class to decode counterparty transactions without a need for counterpartyd
33
+
29
34
  _Version 1.1_
30
35
  * Minor Updates to support changes in counterpartyd 1.1
31
36
  * Removed support for relaying transactions through counterparty
@@ -16,7 +16,7 @@ Gem::Specification.new do |gem|
16
16
  gem.required_ruby_version = '>= 1.9'
17
17
  gem.license = 'LGPL'
18
18
 
19
- ['rest-client', 'bitcoin-ruby', 'ffi'].each do |dependency|
19
+ ['rest-client', 'bitcoin-ruby', 'ffi', 'ruby-rc4'].each do |dependency|
20
20
  gem.add_runtime_dependency dependency
21
21
  end
22
22
  ['rspec', 'rspec-its', 'rake', 'rdoc'].each do |dependency|
@@ -24,6 +24,16 @@ class BlockrIo
24
24
  @is_testing
25
25
  end
26
26
 
27
+ def listunspent(addr, include_unconfirmed = false)
28
+ query = [addr,(include_unconfirmed) ? '?unconfirmed=1' : nil ].join
29
+ json_get('address', 'unspent', query)['data']['unspent']
30
+ end
31
+
32
+ # Shows all the transactions that are unconfirmed for the provided address:
33
+ def listunconfirmed(addr)
34
+ json_get('address','unconfirmed',addr)['data']['unconfirmed']
35
+ end
36
+
27
37
  private
28
38
 
29
39
  def request(*path, &block)
@@ -0,0 +1,119 @@
1
+ #encoding: utf-8
2
+
3
+ # Inspriration heavily lifted from:
4
+ # - https://github.com/tokenly/counterparty-transaction-parser
5
+ module Counterparty
6
+ class TxDecode
7
+ class UndefinedBehavior < StandardError; end # If you find one of these, lmk!
8
+ class InvalidOpReturn < StandardError; end
9
+ class InvalidOutput < StandardError; end
10
+ class MultisigUnsupported < StandardError; end
11
+
12
+ DEFAULT_PREFIX = 'CNTRPRTY'
13
+
14
+ OP_RETURN_PARTS = /^OP_RETURN ([a-z0-9]+)$/
15
+ P2PKH_PARTS = /^OP_DUP OP_HASH160 ([a-z0-9]+) OP_EQUALVERIFY OP_CHECKSIG$/
16
+ OP_MULTISIG_PARTS = /^[12] ([a-z0-9 ]+) ([23]) OP_CHECKMULTISIG$/
17
+
18
+ attr_accessor :sender_addr, :receiver_addr, :decrypt_key, :data, :prefix
19
+
20
+ def initialize(tx, options = {})
21
+ @prefix = options[:prefix] || DEFAULT_PREFIX
22
+ @decrypt_key = options[:decrypt_key] || [tx.inputs[0].prev_out.reverse_hth].pack('H*')
23
+
24
+ parse! (tx.respond_to? :outputs) ?
25
+ tx.outputs.collect{|out| out.parsed_script.to_string } : tx
26
+ end
27
+
28
+ def decrypt(chunk)
29
+ RC4.new(decrypt_key).decrypt chunk
30
+ end
31
+
32
+ private
33
+
34
+ def prefixed?(data, offset = 1)
35
+ data[offset...(prefix.length+offset)] == prefix
36
+ end
37
+
38
+ # This determines if the supplied operation is a non-data
39
+ def is_non_prefixed_p2pkh?(op)
40
+ P2PKH_PARTS.match(op) && !prefixed?(decrypt([$1].pack('H*')))
41
+ end
42
+
43
+ def hash160_from_p2pkh(op)
44
+ Bitcoin.hash160_to_address $1 if P2PKH_PARTS.match op
45
+ end
46
+
47
+ # Note that this isn't exactly the way counterparty parses the transactions.
48
+ # But , it reads cleaner, and worked on every transaction I could find.
49
+ # Mostly the difference is that the counterparty version is a loop that
50
+ # collects P2PKH's anywhere in the outputs, whereas this block takes a sender
51
+ # or receiver address from the top and bottom only
52
+ def parse!(outputs)
53
+ return if @data
54
+
55
+ # So typically, the first output is a P2PKH with the receiver address:
56
+ @receiver_addr = hash160_from_p2pkh outputs.shift if is_non_prefixed_p2pkh? outputs.first
57
+
58
+ # Parse the sender address:
59
+ @sender_addr = hash160_from_p2pkh outputs.pop if is_non_prefixed_p2pkh? outputs.last
60
+
61
+ @data = outputs.collect{|out|
62
+ # This weirdo line will send the regex matches to the operation handler
63
+ # that matches the line
64
+ send (case out
65
+ when OP_RETURN_PARTS then :data_from_opreturn
66
+ when P2PKH_PARTS then :data_from_opchecksig
67
+ when OP_MULTISIG_PARTS then :data_from_opcheckmultisig
68
+ else raise InvalidOutput
69
+ end), *$~.to_a[1..-1]
70
+ }.compact.join
71
+ end
72
+
73
+ def data_from_opreturn(data)
74
+ chunk = [data].pack('H*')
75
+
76
+ raise InvalidOpReturn if chunk.nil?
77
+
78
+ data = decrypt chunk
79
+
80
+ raise InvalidOpReturn unless prefixed?(data,0)
81
+
82
+ data[prefix.length..-1]
83
+ end
84
+
85
+ def data_from_opchecksig(pubkeyhash_text)
86
+ chunk = decrypt [pubkeyhash_text].pack('H*')
87
+
88
+ # This should get picked up by the sender and receiver pop/shift in parse!
89
+ # However, the counterparty lib would parse these obtuse addresses typically
90
+ # ATM - I can't find one in the wild
91
+ raise UndefinedBehavior unless prefixed? chunk
92
+
93
+ chunk_length = chunk[0].ord
94
+ chunk[(1+prefix.length)...chunk_length+1]
95
+ end
96
+
97
+ def data_from_opcheckmultisig(pubkeys_op, n_signatures_op)
98
+ pubkeys, n_signatures = pubkeys_op.split(' '), n_signatures_op.to_i
99
+
100
+ # There's no data in the last pubkey:
101
+ chunk = pubkeys[0...-1].collect{ |pubkey|
102
+ [pubkey].pack('H*')[1...-1] # Skip sign byte and nonce byte.
103
+ }.reduce(:+)
104
+
105
+ data = decrypt chunk
106
+
107
+ # Multisig transactions will break here. I haven't actually collected enough
108
+ # of these samples yet to really test, but it seems they are typically are
109
+ # at the top of the output stack:
110
+ raise MultisigUnsupported unless prefixed? data
111
+
112
+ # Padding byte in each output (instead of just in the last one) so that
113
+ # encoding methods may be mixed. Also, it’s just not very much data.
114
+ chunk_length = data[0].ord
115
+
116
+ data[1..chunk_length][prefix.length..-1]
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,135 @@
1
+ #encoding: utf-8
2
+
3
+ # Inspriration heavily lifted from:
4
+ # - https://github.com/CounterpartyXCP/counterparty-lib/blob/master/counterpartylib/lib/transaction.py
5
+ module Counterparty
6
+ class TxEncode
7
+ class MissingPubkey < StandardError; end
8
+ class MissingSenderAddr < StandardError; end
9
+ class InvalidPubkey < StandardError; end
10
+ class InvalidPubkeyGenerated < StandardError; end
11
+ class DataTooLarge < StandardError; end
12
+
13
+ PREFIX = 'CNTRPRTY'
14
+
15
+ P2PKH = 'OP_DUP OP_HASH160 %s OP_EQUALVERIFY OP_CHECKSIG'
16
+ MULTISIG = '1 %s %s OP_CHECKMULTISIG'
17
+ OPRETURN = 'OP_RETURN %s'
18
+
19
+ # 33 is the size of a pubkey, there are two pubkeys in a multisig, 1 byte
20
+ # is lost for the data length byte, and two bytes are lost on each key for
21
+ # the data_to_pubkey inefficiency
22
+ BYTES_IN_MULTISIG = (33 * 2) - 1 - 2 - 2
23
+ BYTES_IN_PUBKEYHASH = 20 - 1
24
+ BYTES_IN_OPRETURN = 40
25
+
26
+ attr_accessor :sender_addr, :sender_pubkey, :receiver_addr, :encrypt_key,
27
+ :source_data, :prefix
28
+
29
+ def initialize(encrypt_key, source_data, options = {})
30
+ @source_data, @encrypt_key = source_data, encrypt_key
31
+
32
+ if options[:sender_pubkey]
33
+ @sender_pubkey = options[:sender_pubkey]
34
+ @sender_addr = Bitcoin.pubkey_to_address(sender_pubkey)
35
+ elsif options.has_key? :sender_addr
36
+ @sender_addr = options[:sender_addr]
37
+ else
38
+ raise MissingSenderAddr
39
+ end
40
+
41
+ @receiver_addr = options[:receiver_addr] if options.has_key? :receiver_addr
42
+
43
+ @prefix = options[:prefix] || PREFIX
44
+ end
45
+
46
+ def to_opmultisig
47
+ raise MissingPubkey unless sender_pubkey
48
+
49
+ data_length = BYTES_IN_MULTISIG-prefix.length
50
+ p2pkh_wrap collect_chunks(source_data,data_length){|chunk|
51
+ padding = 0.chr * (data_length-chunk.length)
52
+
53
+ data = encrypt [(chunk.length+prefix.length).chr,prefix, chunk, padding].join
54
+
55
+ data_keys = [(0...31), (31...62)].collect{|r| data_to_pubkey data[r] }
56
+
57
+ MULTISIG % [(data_keys + [sender_pubkey]).join(' '), 3]
58
+ }
59
+ end
60
+
61
+ def to_pubkeyhash
62
+ p2pkh_wrap collect_chunks(source_data, BYTES_IN_PUBKEYHASH-prefix.length){ |chunk|
63
+ data_length = prefix.length + chunk.length
64
+
65
+ padding = 0.chr * (BYTES_IN_PUBKEYHASH - data_length)
66
+
67
+ enc_chunk = encrypt [(data_length).chr, prefix, chunk, padding].join
68
+
69
+ P2PKH % enc_chunk.unpack('H*').first
70
+ }
71
+ end
72
+
73
+ def to_opreturn
74
+ # I'm fairly certain that using more than one OP_RETURN per transaction is
75
+ # unstandard behavior right now
76
+ raise DataTooLarge if (source_data.length + prefix.length) > BYTES_IN_OPRETURN
77
+
78
+ data = encrypt [prefix,source_data].join
79
+
80
+ p2pkh_wrap( OPRETURN % data.unpack('H*').first )
81
+ end
82
+
83
+ def encrypt(chunk)
84
+ RC4.new(encrypt_key).encrypt chunk
85
+ end
86
+
87
+ private
88
+
89
+ def p2pkh_wrap(operation)
90
+ [ (receiver_addr) ? P2PKH % Bitcoin.hash160_from_address(receiver_addr) : nil,
91
+ operation,
92
+ P2PKH % Bitcoin.hash160_from_address(sender_addr) ].flatten.compact
93
+ end
94
+
95
+ # Take a too short data pubkey and make it look like a real pubkey.
96
+ # Take an obfuscated chunk of data that is two bytes too short to be a pubkey and
97
+ # add a sign byte to its beginning and a nonce byte to its end. Choose these
98
+ # bytes so that the resulting sequence of bytes is a fully valid pubkey (i.e. on
99
+ # the ECDSA curve). Find the correct bytes by guessing randomly until the check
100
+ # passes. (In parsing, these two bytes are ignored.)
101
+ #
102
+ # NOTE: This function is named "make_fully_valid" in the official code.
103
+ def data_to_pubkey(bytes)
104
+ raise InvalidPubkey unless bytes.length == 31
105
+
106
+ random_bytes = Digest::SHA256.digest bytes
107
+
108
+ # Deterministically generated, for unit tests.
109
+ sign = (random_bytes[0].ord & 1) + 2
110
+ nonce = initial_nonce = random_bytes[1].ord
111
+
112
+ begin
113
+ nonce += 1
114
+ next if nonce == initial_nonce
115
+
116
+ ret = (sign.chr + bytes + (nonce % 256).chr).unpack('H*').first
117
+
118
+ # Note that 256 is the exclusive limit:
119
+ end until Bitcoin.valid_pubkey? ret
120
+
121
+ # I don't actually think this is ever possible. Note that we return 66 bytes
122
+ # as this is string of hex, and not the bytes themselves:
123
+ raise InvalidPubkeyGenerated unless ret.length == 66
124
+
125
+ ret
126
+ end
127
+
128
+ # This is a little helper method that lets us split our binary data into
129
+ # chunks for further processing
130
+ def collect_chunks(data,chunk_length, &block)
131
+ (source_data.length.to_f / chunk_length).ceil.times.collect{|i|
132
+ block.call source_data.slice(i*chunk_length, chunk_length) }
133
+ end
134
+ end
135
+ end
@@ -1,4 +1,4 @@
1
1
  module Counterparty
2
2
  # The library version string
3
- VERSION = "1.1.0"
3
+ VERSION = "1.2.0"
4
4
  end
@@ -2,9 +2,12 @@ require 'json'
2
2
  require 'rest_client'
3
3
  require 'open-uri'
4
4
  require 'bitcoin'
5
+ require 'rc4'
5
6
 
6
7
  require 'blockr_io'
7
8
  require 'counterparty/raw_tx'
9
+ require 'counterparty/tx_decode'
10
+ require 'counterparty/tx_encode'
8
11
  require 'counterparty/version'
9
12
  require 'counterparty/resource'
10
13
  require 'counterparty/resources'
@@ -61,8 +61,22 @@ describe BlockrIo do
61
61
  end
62
62
  end
63
63
 
64
+ describe "#listunspent" do
65
+ it "should list unspent transactions" do
66
+ unspents = blockr_main.listunspent('1CounterpartyXXXXXXXXXXXXXXXUWLpVr')
67
+
68
+ expect(unspents.length).to eq(2620)
69
+ expect(unspents.first.tap{|u| u.delete('confirmations') }).to eq( {
70
+ "tx"=>"bcd6fd6997d26ae12caef102f5e9631ee2ed1e38eaa16547a51d908f4c5ddac8",
71
+ "amount"=>"0.00005430", "n"=>0,
72
+ "script"=>"76a914818895f3dc2c178629d3d2d8fa3ec4a3f817982188ac"} )
73
+
74
+ end
75
+ end
76
+
64
77
  describe "#sendrawtransaction" do
65
78
  # I think the way to test this is simply to do so in the resource_create
66
79
  end
80
+
67
81
  end
68
82
  end
@@ -0,0 +1,262 @@
1
+ #encoding: utf-8
2
+ require_relative 'spec_helper'
3
+
4
+ # deweller provided some nice unit tests for enconding/decoding transactions.
5
+ # These examples were lifted from there.
6
+ # raw_tx = BlockrIo.new.getrawtransaction ''
7
+ describe Counterparty::TxDecode do
8
+ # This converts the tokenly-unit test hash into what bitcoin-ruby expects:
9
+ def tokenly_json_to_hash(json)
10
+ hash = JSON.parse json
11
+
12
+ { 'ver' => hash['version'], 'lock_time' => hash['locktime'],
13
+ 'in' => hash['vin'].collect{ |ain|
14
+ { 'prev_out' => {'hash' => ain['txid'], 'n' => ain['n']},
15
+ 'scriptSig' => ain['scriptSig']['asm'], 'sequence' => ain['sequence']
16
+ }
17
+ },
18
+ 'out' => hash['vout'].collect{ |aout|
19
+ {'value' => aout['value'], 'n' => aout['n'],
20
+ 'scriptPubKey' => aout['scriptPubKey']['asm'] } } }
21
+ end
22
+
23
+ describe ".parse" do
24
+ it "Tokenly's getSampleCounterpartyTransactionProtocol2()" do
25
+ json = '{"txid":"e0082d1fc37172ccf0f5ebfc3cc54291e463384712f44f32ba4996c02045966f","version":1,"locktime":0,"vin":[{"txid":"8fd9f689f158a426867215dbdee58e9eab6c818097d4bf2bcf0bd1458f3c55ab","vout":2,"scriptSig":{"asm":"3045022100a178c9accd7972cfe30a03c98ff5f684bdf0b144eb415f4a4b7fcff596283f720220267f68a6413093b97a42ed5c2f2811193c1bbdd07d668e3076f99751044c347a01 02f4aef682535628a7e0492b2b5db1aa312348c3095e0258e26b275b25b10290e6","hex":"483045022100a178c9accd7972cfe30a03c98ff5f684bdf0b144eb415f4a4b7fcff596283f720220267f68a6413093b97a42ed5c2f2811193c1bbdd07d668e3076f99751044c347a012102f4aef682535628a7e0492b2b5db1aa312348c3095e0258e26b275b25b10290e6"},"sequence":4294967295,"n":0,"addr":"1AuTJDwH6xNqxRLEjPB7m86dgmerYVQ5G1","valueSat":95270,"value":0.0009527,"doubleSpentTxID":null}],"vout":[{"value":"0.00005430","n":0,"scriptPubKey":{"asm":"OP_DUP OP_HASH160 1407ec32be440f32fc70f4eea810acd98f32aa32 OP_EQUALVERIFY OP_CHECKSIG","hex":"76a9141407ec32be440f32fc70f4eea810acd98f32aa3288ac","reqSigs":1,"type":"pubkeyhash","addresses":["12pv1K6LTLPFYXcCwsaU7VWYRSX7BuiF28"]}},{"value":"0.00002500","n":1,"scriptPubKey":{"asm":"1 0276d539826e5ec10fed9ef597d5bfdac067d287fb7f06799c449971b9ddf9fec6 02af7efeb1f7cf0d5077ae7f7a59e2b643c5cd01fb55221bf76221d8c8ead92bf0 02f4aef682535628a7e0492b2b5db1aa312348c3095e0258e26b275b25b10290e6 3 OP_CHECKMULTISIG","hex":"51210276d539826e5ec10fed9ef597d5bfdac067d287fb7f06799c449971b9ddf9fec62102af7efeb1f7cf0d5077ae7f7a59e2b643c5cd01fb55221bf76221d8c8ead92bf02102f4aef682535628a7e0492b2b5db1aa312348c3095e0258e26b275b25b10290e653ae","reqSigs":1,"type":"multisig","addresses":["17MPn1QXt1SLqKWy3NPmJQ7iT5dJKRhCU7","12oEzNKh5TQpKDP1vfeTGnSjoxkboo1m5u","1AuTJDwH6xNqxRLEjPB7m86dgmerYVQ5G1"]}},{"value":"0.00086340","n":2,"scriptPubKey":{"asm":"OP_DUP OP_HASH160 6ca4b6b20eac497e9ca94489c545a3372bdd2fa7 OP_EQUALVERIFY OP_CHECKSIG","hex":"76a9146ca4b6b20eac497e9ca94489c545a3372bdd2fa788ac","reqSigs":1,"type":"pubkeyhash","addresses":["1AuTJDwH6xNqxRLEjPB7m86dgmerYVQ5G1"]}}],"valueOut":0.0009427,"size":340,"valueIn":0.0009527,"fees":0.00001}'
26
+
27
+ tx = Bitcoin::P::Tx.from_hash( tokenly_json_to_hash(json) )
28
+ record = Counterparty::TxDecode.new tx
29
+
30
+ expect(record.data).to eq("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\xFA\xDF\x00\x00\x00\x17Hv\xE8\x00".force_encoding('ASCII-8BIT'))
31
+ expect(record.receiver_addr).to eq('12pv1K6LTLPFYXcCwsaU7VWYRSX7BuiF28')
32
+ expect(record.sender_addr).to eq('1AuTJDwH6xNqxRLEjPB7m86dgmerYVQ5G1')
33
+ end
34
+
35
+ it "Tokenly's getSampleCounterpartyTransaction3()" do
36
+ json = '{"txid":"24c9f9dd130591959b8f2e2e6d0133de028138bf73dfe14cc3de0fbb151812bd","version":1,"locktime":0,"vin":[{"txid":"e7f9319de85661c33130e80b7df16733164892eeb2e1fb044e5ac5de7a3269b7","vout":0,"scriptSig":{"asm":"304402205267657bb7ea5542b8fd32502e78dc3903e5781de8b8a5a119abbd382691a98e02204c47b7aa5940c030def956a4e91be16a692c09c7194a6fdec3054457c99e70c701 0257b0d96d1fe64fbb95b2087e68592ee016c50f102d8dcf776ed166473f27c690","hex":"47304402205267657bb7ea5542b8fd32502e78dc3903e5781de8b8a5a119abbd382691a98e02204c47b7aa5940c030def956a4e91be16a692c09c7194a6fdec3054457c99e70c701210257b0d96d1fe64fbb95b2087e68592ee016c50f102d8dcf776ed166473f27c690"},"sequence":4294967295,"n":0,"addr":"1291Z6hofAAvH8E886cN9M5uKB1VvwBnup","valueSat":5430,"value":0.0000543,"doubleSpentTxID":null},{"txid":"d800ef4c33542c90bcfe4cd0c2fc2c0d120877ec933ca869177a77eb8b42077e","vout":1,"scriptSig":{"asm":"3045022100e43310957b541c51e00c3076393bf93c23dd72306a012f0ebe1024218269045d022029b5218047adf59186d53dbff7a249f82003e923a782cdfd75f8871b89c819b801 0257b0d96d1fe64fbb95b2087e68592ee016c50f102d8dcf776ed166473f27c690","hex":"483045022100e43310957b541c51e00c3076393bf93c23dd72306a012f0ebe1024218269045d022029b5218047adf59186d53dbff7a249f82003e923a782cdfd75f8871b89c819b801210257b0d96d1fe64fbb95b2087e68592ee016c50f102d8dcf776ed166473f27c690"},"sequence":4294967295,"n":1,"addr":"1291Z6hofAAvH8E886cN9M5uKB1VvwBnup","valueSat":801320,"value":0.0080132,"doubleSpentTxID":null}],"vout":[{"value":"0.00005430","n":0,"scriptPubKey":{"asm":"OP_DUP OP_HASH160 9c2401388e6d2752a496261e9130cd54ddb2b262 OP_EQUALVERIFY OP_CHECKSIG","hex":"76a9149c2401388e6d2752a496261e9130cd54ddb2b26288ac","reqSigs":1,"type":"pubkeyhash","addresses":["1FEbYaghvr7V53B9csjQTefUtBBQTaDFvN"]}},{"value":"0.00002500","n":1,"scriptPubKey":{"asm":"1 035240874259b8f93dffc6ffa29b09d0d06dfb072d9646ae777480a2c521bfdbb1 0264f1dd503423e8305e19fc77b4e26dc8ec8a8f500b1bec580112af8c64e74b1b 0257b0d96d1fe64fbb95b2087e68592ee016c50f102d8dcf776ed166473f27c690 3 OP_CHECKMULTISIG","hex":"5121035240874259b8f93dffc6ffa29b09d0d06dfb072d9646ae777480a2c521bfdbb1210264f1dd503423e8305e19fc77b4e26dc8ec8a8f500b1bec580112af8c64e74b1b210257b0d96d1fe64fbb95b2087e68592ee016c50f102d8dcf776ed166473f27c69053ae","reqSigs":1,"type":"multisig","addresses":["1J7TTrHcWQgs37Es8PFKcaoJmUvGRGsEzY","126HYzAnxybKoHpkmrMBSSu3KnqzUgEHGc","1291Z6hofAAvH8E886cN9M5uKB1VvwBnup"]}},{"value":"0.00793820","n":2,"scriptPubKey":{"asm":"OP_DUP OP_HASH160 0c7bea5ae61ccbc157156ffc9466a54b07bfe951 OP_EQUALVERIFY OP_CHECKSIG","hex":"76a9140c7bea5ae61ccbc157156ffc9466a54b07bfe95188ac","reqSigs":1,"type":"pubkeyhash","addresses":["1291Z6hofAAvH8E886cN9M5uKB1VvwBnup"]}}],"valueOut":0.0080175,"size":487,"valueIn":0.0080675,"fees":0.00005}'
37
+
38
+ tx = Bitcoin::P::Tx.from_hash( tokenly_json_to_hash(json) )
39
+ record = Counterparty::TxDecode.new tx
40
+
41
+ expect(record.data).to eq("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\xFA\xDF\x00\x00\x00\x00\v\xEB\xC2\x00".force_encoding('ASCII-8BIT'))
42
+ expect(record.receiver_addr).to eq('1FEbYaghvr7V53B9csjQTefUtBBQTaDFvN')
43
+ expect(record.sender_addr).to eq('1291Z6hofAAvH8E886cN9M5uKB1VvwBnup')
44
+ end
45
+
46
+
47
+ it "Tokenly's getSampleCounterpartyTransaction4()" do
48
+ json = '{"txid":"2d1fea72ea4be25793d8a2e254c6dc4aacfac8978ce0cc4729fe1418649c8f1e","version":1,"locktime":0,"vin":[{"txid":"a6edb86171fc7736389f20bc63542255dbbfa2dcd173fc079414adab7f548071","vout":0,"scriptSig":{"asm":"3044022038397429f0a49e80690eb143e63d83c097288b2c1ea90167688997e8a75a3c8402204e48260b4440001d402b40a33183dc5d54d5ced64670b0e5b72373392c8481d501 034bf23d14fa8aa9e8ebfee6e0bf986fa36ad61434068b89b7a8801506ed5060bb","hex":"473044022038397429f0a49e80690eb143e63d83c097288b2c1ea90167688997e8a75a3c8402204e48260b4440001d402b40a33183dc5d54d5ced64670b0e5b72373392c8481d50121034bf23d14fa8aa9e8ebfee6e0bf986fa36ad61434068b89b7a8801506ed5060bb"},"sequence":4294967295,"n":0,"addr":"1MFHQCPGtcSfNPXAS6NryWja3TbUN9239Y","valueSat":5430,"value":0.0000543,"doubleSpentTxID":null},{"txid":"31aa31fb22cd24d54b68ef7390ed39db09f2e4cbae1c227b2f78087f3edf4077","vout":1,"scriptSig":{"asm":"30440220189f79d7c86884d69f35cb7d8b96916bc3001c522a2025471675a6835fc45b7d02203345a31b0abb79035722a9ed5381fd34380f4e9cc418a5ea522034e50ea1f2e901 034bf23d14fa8aa9e8ebfee6e0bf986fa36ad61434068b89b7a8801506ed5060bb","hex":"4730440220189f79d7c86884d69f35cb7d8b96916bc3001c522a2025471675a6835fc45b7d02203345a31b0abb79035722a9ed5381fd34380f4e9cc418a5ea522034e50ea1f2e90121034bf23d14fa8aa9e8ebfee6e0bf986fa36ad61434068b89b7a8801506ed5060bb"},"sequence":4294967295,"n":1,"addr":"1MFHQCPGtcSfNPXAS6NryWja3TbUN9239Y","valueSat":1717640,"value":0.0171764,"doubleSpentTxID":null}],"vout":[{"value":"0.00005430","n":0,"scriptPubKey":{"asm":"OP_DUP OP_HASH160 fd84ff1f2cc1b0299165e2804fccd6fb0bd48d0b OP_EQUALVERIFY OP_CHECKSIG","hex":"76a914fd84ff1f2cc1b0299165e2804fccd6fb0bd48d0b88ac","reqSigs":1,"type":"pubkeyhash","addresses":["1Q7VHJDEzVj7YZBVseQWgYvVj3DWDCLwDE"]}},{"value":"0.00000000","n":1,"scriptPubKey":{"asm":"OP_RETURN 2c54fff6d3e165e008f5ec45a06951e6b6fb4a162fcfec34aa1f0dd8","hex":"6a1c2c54fff6d3e165e008f5ec45a06951e6b6fb4a162fcfec34aa1f0dd8","type":"nulldata"}},{"value":"0.01712640","n":2,"scriptPubKey":{"asm":"OP_DUP OP_HASH160 de1607744008a3edeabae06365a9aa2b131d5dc2 OP_EQUALVERIFY OP_CHECKSIG","hex":"76a914de1607744008a3edeabae06365a9aa2b131d5dc288ac","reqSigs":1,"type":"pubkeyhash","addresses":["1MFHQCPGtcSfNPXAS6NryWja3TbUN9239Y"]}}],"blockhash":"00000000000000000d7fbe3a59b9d37380fb46a79289e2011396721c433a7883","confirmations":1,"time":1428589045,"blocktime":1428589045,"valueOut":0.0171807,"size":411,"valueIn":0.0172307,"fees":0.00005}'
49
+
50
+ tx = Bitcoin::P::Tx.from_hash( tokenly_json_to_hash(json) )
51
+ record = Counterparty::TxDecode.new tx
52
+
53
+ expect(record.data).to eq("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\xFA\xDF\x00\x00\x00\x00\x05\xF5\xE1\x00".force_encoding('ASCII-8BIT'))
54
+ end
55
+
56
+ it "Tokenly's getSampleCounterpartyTransaction5()" do
57
+ json = '{"txid":"48e07bdad04f869850ccdb11b5e6a9e89ee8023111eb4f2e293d3e8ef75befee","version":1,"locktime":0,"vin":[{"txid":"cf8fa29cf63938a787e732c85071695668b9e00bfedff807dfbdc85a6ad6a696","vout":0,"scriptSig":{"asm":"304502210089af043911012c558bd11392d4346da725cd35822c1c6c0140293fed3344176d02207e6ad3945cb6580e654ac579a3ffdc01b93e54c4babc55bde6aa2b97ddf3f0af01 02b0610c458d67d76e348c6bb2f29f66d272e2c66bd23747ac401fefa45d2fc7a0","hex":"48304502210089af043911012c558bd11392d4346da725cd35822c1c6c0140293fed3344176d02207e6ad3945cb6580e654ac579a3ffdc01b93e54c4babc55bde6aa2b97ddf3f0af012102b0610c458d67d76e348c6bb2f29f66d272e2c66bd23747ac401fefa45d2fc7a0"},"sequence":4294967295,"n":0,"addr":"12iVwKP7jCPnuYy7jbAbyXnZ3FxvgLwvGK","valueSat":5430,"value":0.0000543,"doubleSpentTxID":null},{"txid":"d6e1e95bae2a4715dce049f464525af1f118876b7e79c311e1fa4c2bf77f4df4","vout":2,"scriptSig":{"asm":"30440220459ef45b40a80a9dc1cb2c33d1f5ddd8d464c4a607dbe2df83049d69b35c7b960220134b69e807eb2bebc3339bfb60a7de5b86c801f64d176fc704a3ce9132e8509301 02b0610c458d67d76e348c6bb2f29f66d272e2c66bd23747ac401fefa45d2fc7a0","hex":"4730440220459ef45b40a80a9dc1cb2c33d1f5ddd8d464c4a607dbe2df83049d69b35c7b960220134b69e807eb2bebc3339bfb60a7de5b86c801f64d176fc704a3ce9132e85093012102b0610c458d67d76e348c6bb2f29f66d272e2c66bd23747ac401fefa45d2fc7a0"},"sequence":4294967295,"n":1,"addr":"12iVwKP7jCPnuYy7jbAbyXnZ3FxvgLwvGK","valueSat":1760000,"value":0.0176,"doubleSpentTxID":null}],"vout":[{"value":"0.00005430","n":0,"scriptPubKey":{"asm":"OP_DUP OP_HASH160 cab7d87116e620e10a69e666ec6494d4607631e7 OP_EQUALVERIFY OP_CHECKSIG","hex":"76a914cab7d87116e620e10a69e666ec6494d4607631e788ac","reqSigs":1,"type":"pubkeyhash","addresses":["1KUsjZKrkd7LYRV7pbnNJtofsq1HAiz6MF"]}},{"value":"0.00000000","n":1,"scriptPubKey":{"asm":"OP_RETURN fb706d6b2839cfd52a4b50cb135f18cf9e0b280ca45b2da5694229f0","hex":"6a1cfb706d6b2839cfd52a4b50cb135f18cf9e0b280ca45b2da5694229f0","type":"nulldata"}},{"value":"0.01755000","n":2,"scriptPubKey":{"asm":"OP_DUP OP_HASH160 12d155cefea286e9d3cda6cb64cd8d26a5b95780 OP_EQUALVERIFY OP_CHECKSIG","hex":"76a91412d155cefea286e9d3cda6cb64cd8d26a5b9578088ac","reqSigs":1,"type":"pubkeyhash","addresses":["12iVwKP7jCPnuYy7jbAbyXnZ3FxvgLwvGK"]}}],"valueOut":0.0176043,"size":412,"valueIn":0.0176543,"fees":0.00005}'
58
+
59
+ tx = Bitcoin::P::Tx.from_hash( tokenly_json_to_hash(json) )
60
+ record = Counterparty::TxDecode.new tx
61
+
62
+ expect(record.data).to eq("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\xFA\xDF\x00\x00\x00\x01*\x05\xF2\x00".force_encoding('ASCII-8BIT'))
63
+ expect(record.receiver_addr).to eq('1KUsjZKrkd7LYRV7pbnNJtofsq1HAiz6MF')
64
+ expect(record.sender_addr).to eq('12iVwKP7jCPnuYy7jbAbyXnZ3FxvgLwvGK')
65
+ end
66
+
67
+ it "decodes a random counterparty transaction" do
68
+ # This was from a random Counterparty Broadcast. Txid:
69
+ # eae1fd843f267d756c765b3e84ff33cd3f7dcde4df671c53b2e3465ba9f1b94e
70
+
71
+ raw_tx = '0100000001c77af36618fa11f91152608a6ed50'+
72
+ 'eab0fed0c9ace1a1f60444e8abb15d5cdd6010000006b4830450220243fa1706a7'+
73
+ '708ffa5313a04935fd543f5fd04d43f3f8d6c46e94502dfabcb08022100a682848'+
74
+ 'c79356ab47e17b3f10ed91e45c72ad0fc866c2e4a4bb25826ef9ac00f01210216b'+
75
+ '6c3047c80b4e2fcbed0df1b265d73dbef174291fcb4cdc427cef12ea3cf3cfffff'+
76
+ 'fff03781e00000000000069512103d468e197eaad3c41aac3aca739bb6a6a9a96f'+
77
+ '7c8446ae8055d3889b7a3d5219f21021875e020f9fac3f2654d173b110b0354db4'+
78
+ 'ff931b5aa069bb090a15521164a73210216b6c3047c80b4e2fcbed0df1b265d73d'+
79
+ 'bef174291fcb4cdc427cef12ea3cf3c53ae781e00000000000069512103f968e19'+
80
+ '7eaad3c41aaa0cfc5559c59a8412907c8446ae8055d3889b7a3fd63092102543aa'+
81
+ '36baab982bc451b5269584d5a799a0bbd63f0f955bb84fdcc244020238a210216b'+
82
+ '6c3047c80b4e2fcbed0df1b265d73dbef174291fcb4cdc427cef12ea3cf3c53ae3'+
83
+ '3009718000000001976a914b14a2f25ceaa17b72a089813eae8f33f9dddeb0c88a'+
84
+ 'c00000000'
85
+
86
+
87
+ tx = Bitcoin::P::Tx.new [raw_tx].pack('H*')
88
+ record = Counterparty::TxDecode.new tx
89
+
90
+ expect(record.data).to eq("\x00\x00\x00\x1EUT\xA9\xA2\xBF\xF0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00(BLOCKSCAN VERIFY-ADDRESS 4mmqa6iccbrrgky".force_encoding('ASCII-8BIT'))
91
+ expect(record.sender_addr).to eq('1HARUMuoSXftAwY6jxMUutc9uKSCK9zxzF')
92
+ expect(record.receiver_addr).to be_nil
93
+ end
94
+
95
+ it "decodes a pubkeyhash encoding" do
96
+ # This was from Txid:
97
+ # '76133a842ced8d76047e070924bca66652b19581803079f200d35fd824499940'
98
+ raw_tx = '01000000011b4e667cf0b715fa95be6baa6b505'+
99
+ '78fd9c3fa15fb0a5554aeb5f3991e672c64010000006a47304402204dea7f4824a'+
100
+ 'c40fc501fab3e341c2e47670a81b38820854b6f5540c673945a8a0220110446d7a'+
101
+ '4e76df07041ef76f137485f0d0fd9114d612e784e2721954129c48701210321bab'+
102
+ '6d17f75ebbbdd71793fa9c1136b537e5679ea2fc153fa1cb0884d038834fffffff'+
103
+ 'f0436150000000000001976a914748e483222863a836a421df1a9395bbd835bdfd'+
104
+ 'a88ac36150000000000001976a91461e09442c872dabb980a7a86a04323a62512e'+
105
+ 'c5d88ac36150000000000001976a91463e09442c872dabb98467a86a0432653c40'+
106
+ 'c96c088ac20867700000000001976a914ce27246a0a6ca54dfa1f780ccd5cb3d0c'+
107
+ '73a75b288ac00000000'
108
+
109
+ tx = Bitcoin::P::Tx.new [raw_tx].pack('H*')
110
+ record = Counterparty::TxDecode.new tx
111
+ expect(record.data).to eq("\x00\x00\x00\x00\x00\x00\x00\x00\x1Ez\x9DL\x00\x00\x00\x00\x05\xF5\xE1\x00".force_encoding('ASCII-8BIT'))
112
+ expect(record.receiver_addr).to eq('1BdHqBSfUqv77XtBSeofH6XwHHczZxKRUF')
113
+ expect(record.sender_addr).to eq('1Ko36AjTKYh6EzToLU737Bs2pxCsGReApK')
114
+ end
115
+
116
+ it "decodes these weird two output OP_RETURNs" do
117
+ # The reason this is a weird transaction is
118
+ # because the size of the inputs happens to equal dust_size + tx fee
119
+ #
120
+ # This was from Txid:
121
+ # '05f89f3538e762c534fa9c65200c115b9796386ce2eb8f88f3d7b430873ec302'
122
+ raw_tx = '010000000341ba60588bdf72c63ae3641767f59'+
123
+ '5be991e8c70bf970b658d48c2a3446d367a000000006b483045022100c8f219137'+
124
+ '6cc2c0235d8cd66e429fbd7bb0cbe410e35359d6a1a27b903345f1d0220696f72e'+
125
+ 'af67f3bfe96fc7504fe1b9d5455bdde45dba127a1e082152c056706bc012102724'+
126
+ '0dfe6f1b45e009812b9bf0b1dce959f3313e28140185800c9fec814f00351fffff'+
127
+ 'fff713f469f416cd52270f756373d6da00b6829b88240d7aa9f74464f0e77df836'+
128
+ 'a000000006b483045022100a8da4b96afe2a70c69fa9aacf186e2ba0ed03782bd7'+
129
+ 'b4fe70e3e75a4ed62380e02206964db4f0d19a9ed4753ecbd8685fdb6e45e23611'+
130
+ '7ec4eeaca968acb781d9b110121027240dfe6f1b45e009812b9bf0b1dce959f331'+
131
+ '3e28140185800c9fec814f00351ffffffffcdd532ffa6e5742ca99bd5f713777d3'+
132
+ 'b6569152a813e3b351ccb9da82abe456d000000006b48304502210093c57cd43cc'+
133
+ 'ca9a9c7743341c23bba532dc9025f8f4fea7c02d56a4197e2737802207e4a8dec6'+
134
+ '5efe31fef6e9297698207b5d09f8729974a90e70ff85b1ee6029d670121027240d'+
135
+ 'fe6f1b45e009812b9bf0b1dce959f3313e28140185800c9fec814f00351fffffff'+
136
+ 'f0256400000000000001976a9148c2e9372962ce45c5c2f33479499314a71e6ea3'+
137
+ 'd88ac00000000000000001e6a1c00d0dd53993819edb255fc6e348bfcb2092d896'+
138
+ '9d012da6183f8ec6100000000'
139
+
140
+ tx = Bitcoin::P::Tx.new [raw_tx].pack('H*')
141
+ record = Counterparty::TxDecode.new tx
142
+ expect(record.data).to eq("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x05\xF5\xE1\x00".force_encoding('ASCII-8BIT'))
143
+ expect(record.receiver_addr).to eq('1DnDQ1ef1eCuFcexZn1wqXFdtbFTQqE9LH')
144
+ expect(record.sender_addr).to be_nil
145
+ end
146
+
147
+ it "decodes a four output pubkeyhash" do
148
+ # This was from Txid:
149
+ # '76133a842ced8d76047e070924bca66652b19581803079f200d35fd824499940'
150
+ raw_tx = '01000000011b4e667cf0b715fa95be6baa6b505'+
151
+ '78fd9c3fa15fb0a5554aeb5f3991e672c64010000006a47304402204dea7f4824a'+
152
+ 'c40fc501fab3e341c2e47670a81b38820854b6f5540c673945a8a0220110446d7a'+
153
+ '4e76df07041ef76f137485f0d0fd9114d612e784e2721954129c48701210321bab'+
154
+ '6d17f75ebbbdd71793fa9c1136b537e5679ea2fc153fa1cb0884d038834fffffff'+
155
+ 'f0436150000000000001976a914748e483222863a836a421df1a9395bbd835bdfd'+
156
+ 'a88ac36150000000000001976a91461e09442c872dabb980a7a86a04323a62512e'+
157
+ 'c5d88ac36150000000000001976a91463e09442c872dabb98467a86a0432653c40'+
158
+ 'c96c088ac20867700000000001976a914ce27246a0a6ca54dfa1f780ccd5cb3d0c'+
159
+ '73a75b288ac00000000'
160
+
161
+ tx = Bitcoin::P::Tx.new [raw_tx].pack('H*')
162
+ record = Counterparty::TxDecode.new tx
163
+
164
+ expect(record.data).to eq("\x00\x00\x00\x00\x00\x00\x00\x00\x1Ez\x9DL\x00\x00\x00\x00\x05\xF5\xE1\x00".force_encoding('ASCII-8BIT'))
165
+ expect(record.receiver_addr).to eq('1BdHqBSfUqv77XtBSeofH6XwHHczZxKRUF')
166
+ expect(record.sender_addr).to eq('1Ko36AjTKYh6EzToLU737Bs2pxCsGReApK')
167
+ end
168
+
169
+ it "decodes the mother of all multisig broadcasts" do
170
+ # This was from Txid:
171
+ # '14200afba2c8f91664afc37143763e5987a20647db3443c999137cc41b4db6e4'
172
+ # This transaction was enormous, so I'm just going to pull it from the web:
173
+ raw_tx = BlockrIo.new.getrawtransaction '14200afba2c8f91664afc37143763e5987a20647db3443c999137cc41b4db6e4'
174
+
175
+ tx = Bitcoin::P::Tx.new [raw_tx].pack('H*')
176
+ record = Counterparty::TxDecode.new tx
177
+
178
+ expect(record.data).to eq("\x00\x00\x00\x1EUj\x18\xE0\xBF\xF0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Commerce on the Internet has come to rely almost exclusively on financial institutions serving as trusted third parties to process electronic payments. While the system works well enough for most transactions, it still suffers from the inherent weaknesses of the trust based model. Completely non-reversible transactions are not really possible, since financial institutions cannot avoid mediating disputes. The cost of mediation increases transaction costs, limiting the minimum practical transaction size and cutting off the possibility for small casual transactions, and there is a broader cost in the loss of ability to make non-reversible payments for nonreversible services. With the possibility of reversal, the need for trust spreads. Merchants must be wary of their customers, hassling them for more information than they would otherwise need. A certain percentage of fraud is accepted as unavoidable. These costs and payment uncertainties can be avoided in person by using physical currency, but no mechanism exists to make payments over a communications channel without a trusted party. What is needed is an electronic payment system based on cryptographic proof instead of trust, allowing any two willing parties to transact directly with each other without the need for a trusted third party. Transactions that are computationally impractical to reverse would protect sellers from fraud, and routine escrow mechanisms could easily be implemented to protect buyers. In this paper, we propose a solution to the double-spending problem using a peer-to-peer distributed timestamp server to generate computational proof of the chronological order of transactions. The system is secure as long as honest nodes collectively control more CPU power than any cooperating group of attacker nodes.".force_encoding('ASCII-8BIT'))
179
+ expect(record.sender_addr).to eq('186sRhi5Ux1eKGzx5vRdq1ueGGB5NKLKRr')
180
+ expect(record.receiver_addr).to be_nil
181
+ end
182
+
183
+ it "doesn't support multisig transactions ATM" do
184
+ # Txid:
185
+ # d4153cb6c3756d5198af15a018f50731dcdacae86d5448c7404b7e42adf59942
186
+
187
+ raw_tx = '010000000145a4f089931f677dd5c97c7c5de6e2e748c431726d0a9dc8b200df4250'+
188
+ '596768020000006b483045022100fd881b69b1572587c224e7bf79bc7aba96447946cecb1fb'+
189
+ '66f7c4a7ac140881c022030f91bb9a9c119c8ccf9fdf7d86d123a5c3e791fecc3578433db39'+
190
+ 'b54fed674c01210202baab55d662c40f5846da3ac914fef8acc4c2932dac0120808c3fcc583'+
191
+ 'ad0efffffffff03781e000000000000c95241047664bc75c1eb2df0082e6753fa01fe3ed690'+
192
+ '012236d9629d9e754dc63b540634c5db95700fa337c4e2374519d357ebc4fa2a69b02f30aa9'+
193
+ '2988afdaaad2a2e314104cb88f386eccbccb0b847b69e6ef3570ad5ce2397cd6bd74cd448d1'+
194
+ 'a5de31a5a3e7deadb446bcb25df8ecf45b3aad234e16183b71c2621829572e268c18ccb72f4'+
195
+ '104fb41fed5c73b3fa08f8be7e31982f4fb490d0d5017a65c2ebf0a0bbb930ceff7dba3581c'+
196
+ '941a71035f5a06254364d9deb6de40c1626e10205f840ab11315904c53ae000000000000000'+
197
+ '01e6a1c593b2c1d8269aa039023b56b6487bf8dbedc7b880f42bddbe7388989de7f0b000000'+
198
+ '00001976a9149583a3a598b987d5fa27eae2dc27f004b11277b988ac00000000'
199
+
200
+ tx = Bitcoin::P::Tx.new [raw_tx].pack('H*')
201
+ expect{ Counterparty::TxDecode.new tx }.to raise_error(::Counterparty::TxDecode::MultisigUnsupported)
202
+ end
203
+
204
+ it "Doesn't parse this weird double output send to self" do
205
+ # Txid: http://www.blockscan.com/txInfo/11675374
206
+ # b062d52f7749cf46cbe01e8dd16fe2b7edd6483269c8a0ac5b0b3f8ea6370e5f
207
+
208
+ raw_tx = '01000000015869b4a6e10d9540621b168e9cde9fa45fd79540725a3512c6'+
209
+ 'be63a8ab81d154020000006b483045022100f92d69473147027150680b138b70e1f'+
210
+ '89fef78c8e276f7cd251ebb226fd4c4bb0220673e07a6323c0bc7e927939a062ec2'+
211
+ 'c557b585b45cc2336bbcb0131d15fe835b012102a51147c9e3a554ed35e20cc5ca0'+
212
+ 'fef20e47ae976cfe06a594e135e416bb05e32ffffffff0436150000000000001976'+
213
+ 'a9144de50dc01362d6ad9b4365a56167dae8c029bba188ac3615000000000000197'+
214
+ '6a9149c834113474128c7c59eec778d57cbcca48839be88ac00000000000000001e'+
215
+ '6a1c4a789161a23e6f1be8c311a7aa330f31a9ca450a1cec95caca0df2c89fc97c0'+
216
+ '0000000001976a9144de50dc01362d6ad9b4365a56167dae8c029bba188ac00000000'
217
+
218
+ tx = Bitcoin::P::Tx.new [raw_tx].pack('H*')
219
+ expect{ Counterparty::TxDecode.new tx }.to raise_error(
220
+ ::Counterparty::TxDecode::UndefinedBehavior)
221
+ end
222
+
223
+ it "Data before addresses" do
224
+ # Txid: http://www.blockscan.com/txInfo/11675370
225
+ # 54d181aba863bec612355a724095d75fa49fde9c8e161b6240950de1a6b46958
226
+
227
+ raw_tx = '01000000017b66db9fdbdddc72fe24bfc9a85842d8bd68f75300756b7b7b'+
228
+ 'bff250e2874071020000006a47304402207207e0204153c828ef3357252a52d522a'+
229
+ '07f43ba2024582312f02507c4b57ca1022037f2182ee6f664d235879119c6ff10d5'+
230
+ '3e2dfa6bce0126bcb68af78ce2c4dd32012102a51147c9e3a554ed35e20cc5ca0fe'+
231
+ 'f20e47ae976cfe06a594e135e416bb05e32ffffffff0300000000000000001e6a1c'+
232
+ 'd5a46d783d4d425b6e0c4fe1bcc1bc3fb8827e67e81199ff98d0d2f636150000000'+
233
+ '000001976a9149c834113474128c7c59eec778d57cbcca48839be88ac1b1b7d0000'+
234
+ '0000001976a9144de50dc01362d6ad9b4365a56167dae8c029bba188ac00000000'
235
+
236
+ tx = Bitcoin::P::Tx.new [raw_tx].pack('H*')
237
+ expect{ Counterparty::TxDecode.new tx }.to raise_error(
238
+ ::Counterparty::TxDecode::UndefinedBehavior)
239
+ end
240
+
241
+ it "Doesn't parse this weird double-output spend" do
242
+ # Txid: http://www.blockscan.com/txInfo/11674475
243
+ # 99beec983f9b700629cb3283b5444e837b73790d2e0eec60f00fdb443340d446
244
+
245
+ raw_tx = '0100000001f2e2738960c4f488f0913ebbbb787e3f4db6e953a099275a56'+
246
+ 'e75be340c58424020000006b483045022100f241dfcc797e46978bc2cfd54976dac'+
247
+ '32edb03c5022367bb50bb9bdec45ebaab02206039b0a664cfa3d7190405a1fbdb63'+
248
+ '497bfb066dcd4f70e8a574024823c01cc6012102a51147c9e3a554ed35e20cc5ca0'+
249
+ 'fef20e47ae976cfe06a594e135e416bb05e32ffffffff0436150000000000001976'+
250
+ 'a9149c834113474128c7c59eec778d57cbcca48839be88ac3615000000000000197'+
251
+ '6a914bce6192508e34eba664cfe21dd495c59d5501c2088ac00000000000000001e'+
252
+ '6a1ce85876dd554d039aaee671e845972981b6a0e283de1a7ea8c59df734330c7e0'+
253
+ '0000000001976a9144de50dc01362d6ad9b4365a56167dae8c029bba188ac00000000'
254
+
255
+ tx = Bitcoin::P::Tx.new [raw_tx].pack('H*')
256
+ expect{ Counterparty::TxDecode.new tx }.to raise_error(
257
+ ::Counterparty::TxDecode::UndefinedBehavior)
258
+ end
259
+
260
+ end
261
+ end
262
+
@@ -0,0 +1,179 @@
1
+ # encoding: utf-8
2
+ require_relative 'spec_helper'
3
+
4
+ describe Counterparty::TxEncode do
5
+ describe ".encode" do
6
+ it "Tokenly's getSampleCounterpartyTransactionProtocol2()" do
7
+ encoder = Counterparty::TxEncode.new(
8
+ # Key:
9
+ "\x8F\xD9\xF6\x89\xF1X\xA4&\x86r\x15\xDB\xDE\xE5\x8E\x9E\xABl\x81"+
10
+ "\x80\x97\xD4\xBF+\xCF\v\xD1E\x8F<U\xAB",
11
+ # Data:
12
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\xFA\xDF\x00\x00\x00\x17Hv\xE8\x00",
13
+ :receiver_addr => "12pv1K6LTLPFYXcCwsaU7VWYRSX7BuiF28",
14
+ :sender_pubkey => '02f4aef682535628a7e0492b2b5db1aa312348c3095e0258e26b275b25b10290e6')
15
+
16
+ expect(encoder.to_opmultisig).to eq([
17
+ "OP_DUP OP_HASH160 1407ec32be440f32fc70f4eea810acd98f32aa32 OP_EQUALVERIFY OP_CHECKSIG",
18
+ "1 0276d539826e5ec10fed9ef597d5bfdac067d287fb7f06799c449971b9ddf9fec6 02af7efeb1f7cf0d5077ae7f7a59e2b643c5cd01fb55221bf76221d8c8ead92bf0 02f4aef682535628a7e0492b2b5db1aa312348c3095e0258e26b275b25b10290e6 3 OP_CHECKMULTISIG",
19
+ "OP_DUP OP_HASH160 6ca4b6b20eac497e9ca94489c545a3372bdd2fa7 OP_EQUALVERIFY OP_CHECKSIG"
20
+ ] )
21
+ end
22
+
23
+ it "Tokenly's getSampleCounterpartyTransaction3()" do
24
+ encoder = Counterparty::TxEncode.new(
25
+ # Key:
26
+ "\xE7\xF91\x9D\xE8Va\xC310\xE8\v}\xF1g3\x16H\x92\xEE\xB2\xE1\xFB"+
27
+ "\x04NZ\xC5\xDEz2i\xB7",
28
+ # Data:
29
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\xFA\xDF\x00\x00\x00\x00\v\xEB\xC2\x00",
30
+ :receiver_addr => "1FEbYaghvr7V53B9csjQTefUtBBQTaDFvN",
31
+ :sender_pubkey => "0257b0d96d1fe64fbb95b2087e68592ee016c50f102d8dcf776ed166473f27c690")
32
+
33
+ expect(encoder.to_opmultisig).to eq([
34
+ "OP_DUP OP_HASH160 9c2401388e6d2752a496261e9130cd54ddb2b262 OP_EQUALVERIFY OP_CHECKSIG",
35
+ "1 035240874259b8f93dffc6ffa29b09d0d06dfb072d9646ae777480a2c521bfdbb1 0264f1dd503423e8305e19fc77b4e26dc8ec8a8f500b1bec580112af8c64e74b1b 0257b0d96d1fe64fbb95b2087e68592ee016c50f102d8dcf776ed166473f27c690 3 OP_CHECKMULTISIG",
36
+ "OP_DUP OP_HASH160 0c7bea5ae61ccbc157156ffc9466a54b07bfe951 OP_EQUALVERIFY OP_CHECKSIG"
37
+
38
+ ] )
39
+ end
40
+
41
+ it "Tokenly's getSampleCounterpartyTransaction4()" do
42
+ encoder = Counterparty::TxEncode.new(
43
+ # Key:
44
+ "\xA6\xED\xB8aq\xFCw68\x9F \xBCcT\"U\xDB\xBF\xA2\xDC\xD1s\xFC\a\x94"+
45
+ "\x14\xAD\xAB\x7FT\x80q",
46
+ # Data:
47
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\xFA\xDF\x00\x00\x00\x00"+
48
+ "\x05\xF5\xE1\x00",
49
+ :receiver_addr => "1Q7VHJDEzVj7YZBVseQWgYvVj3DWDCLwDE",
50
+ :sender_addr => '1MFHQCPGtcSfNPXAS6NryWja3TbUN9239Y')
51
+
52
+ expect(encoder.to_opreturn).to eq([
53
+ "OP_DUP OP_HASH160 fd84ff1f2cc1b0299165e2804fccd6fb0bd48d0b OP_EQUALVERIFY OP_CHECKSIG",
54
+ "OP_RETURN 2c54fff6d3e165e008f5ec45a06951e6b6fb4a162fcfec34aa1f0dd8",
55
+ "OP_DUP OP_HASH160 de1607744008a3edeabae06365a9aa2b131d5dc2 OP_EQUALVERIFY OP_CHECKSIG"
56
+ ] )
57
+ end
58
+
59
+ it "Tokenly's getSampleCounterpartyTransaction5()" do
60
+ encoder = Counterparty::TxEncode.new(
61
+ # Key:
62
+ "\xCF\x8F\xA2\x9C\xF698\xA7\x87\xE72\xC8PqiVh\xB9\xE0\v\xFE\xDF\xF8"+
63
+ "\a\xDF\xBD\xC8Zj\xD6\xA6\x96",
64
+ # Data:
65
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\xFA\xDF\x00\x00\x00\x01*"+
66
+ "\x05\xF2\x00",
67
+ :receiver_addr => "1KUsjZKrkd7LYRV7pbnNJtofsq1HAiz6MF",
68
+ :sender_addr => '12iVwKP7jCPnuYy7jbAbyXnZ3FxvgLwvGK')
69
+
70
+ expect(encoder.to_opreturn).to eq([
71
+ "OP_DUP OP_HASH160 cab7d87116e620e10a69e666ec6494d4607631e7 OP_EQUALVERIFY OP_CHECKSIG",
72
+ "OP_RETURN fb706d6b2839cfd52a4b50cb135f18cf9e0b280ca45b2da5694229f0",
73
+ "OP_DUP OP_HASH160 12d155cefea286e9d3cda6cb64cd8d26a5b95780 OP_EQUALVERIFY OP_CHECKSIG"
74
+ ] )
75
+ end
76
+
77
+ it "encodes a four output pubkeyhash" do
78
+ # This was from Txid:
79
+ # '76133a842ced8d76047e070924bca66652b19581803079f200d35fd824499940'
80
+
81
+ encoder = Counterparty::TxEncode.new(
82
+ # Key:
83
+ "d,g\x1E\x99\xF3\xB5\xAETU\n\xFB\x15\xFA\xC3\xD9\x8FWPk\xAAk\xBE"+
84
+ "\x95\xFA\x15\xB7\xF0|fN\e",
85
+ # Data:
86
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x1Ez\x9DL\x00\x00\x00\x00\x05"+
87
+ "\xF5\xE1\x00".force_encoding('UTF-8'),
88
+ :receiver_addr => "1BdHqBSfUqv77XtBSeofH6XwHHczZxKRUF",
89
+ :sender_addr => '1Ko36AjTKYh6EzToLU737Bs2pxCsGReApK')
90
+
91
+ expect(encoder.to_pubkeyhash).to eq([
92
+ 'OP_DUP OP_HASH160 748e483222863a836a421df1a9395bbd835bdfda OP_EQUALVERIFY OP_CHECKSIG',
93
+ 'OP_DUP OP_HASH160 61e09442c872dabb980a7a86a04323a62512ec5d OP_EQUALVERIFY OP_CHECKSIG',
94
+ 'OP_DUP OP_HASH160 63e09442c872dabb98467a86a0432653c40c96c0 OP_EQUALVERIFY OP_CHECKSIG',
95
+ 'OP_DUP OP_HASH160 ce27246a0a6ca54dfa1f780ccd5cb3d0c73a75b2 OP_EQUALVERIFY OP_CHECKSIG',
96
+ ] )
97
+ end
98
+
99
+ it "Encodes the gigantic multsig satoshi broadcast" do
100
+ # This was from Txid:
101
+ # '14200afba2c8f91664afc37143763e5987a20647db3443c999137cc41b4db6e4'
102
+
103
+ encoder = Counterparty::TxEncode.new(
104
+ # Key:
105
+ "\x13\xA2\x19LGG\xC7g\x85\xA7N\xFEQ\xB8xyG\x16E\xDD\xC1&\x8D\xE9"+
106
+ "\xCA\xA6%\xF3\xA9\xA3\x05E",
107
+ # Data:
108
+ "\x00\x00\x00\x1EUj\x18\xE0\xBF\xF0\x00\x00\x00\x00\x00\x00\x00\x00"+
109
+ "\x00\x00Commerce on the Internet has come to rely almost exclusively"+
110
+ " on financial institutions serving as trusted third parties to "+
111
+ "process electronic payments. While the system works well enough for "+
112
+ "most transactions, it still suffers from the inherent weaknesses of "+
113
+ "the trust based model. Completely non-reversible transactions are "+
114
+ "not really possible, since financial institutions cannot avoid "+
115
+ "mediating disputes. The cost of mediation increases transaction "+
116
+ "costs, limiting the minimum practical transaction size and cutting "+
117
+ "off the possibility for small casual transactions, and there is a "+
118
+ "broader cost in the loss of ability to make non-reversible payments "+
119
+ "for nonreversible services. With the possibility of reversal, the "+
120
+ "need for trust spreads. Merchants must be wary of their customers, "+
121
+ "hassling them for more information than they would otherwise need. "+
122
+ "A certain percentage of fraud is accepted as unavoidable. These "+
123
+ "costs and payment uncertainties can be avoided in person by using "+
124
+ "physical currency, but no mechanism exists to make payments over a "+
125
+ "communications channel without a trusted party. What is needed is "+
126
+ "an electronic payment system based on cryptographic proof instead "+
127
+ "of trust, allowing any two willing parties to transact directly "+
128
+ "with each other without the need for a trusted third party. "+
129
+ "Transactions that are computationally impractical to reverse would "+
130
+ "protect sellers from fraud, and routine escrow mechanisms could "+
131
+ "easily be implemented to protect buyers. In this paper, we propose "+
132
+ "a solution to the double-spending problem using a peer-to-peer "+
133
+ "distributed timestamp server to generate computational proof of the "+
134
+ "chronological order of transactions. The system is secure as long "+
135
+ "as honest nodes collectively control more CPU power than any "+
136
+ "cooperating group of attacker nodes.".force_encoding('UTF-8'),
137
+ :sender_pubkey => '02a51147c9e3a554ed35e20cc5ca0fef20e47ae976cfe06a594e135e416bb05e32')
138
+
139
+ expect(encoder.to_opmultisig).to eq([
140
+ '1 027d222586a44cc5d365673cb613c1bb8df9cf6ab74cd825b1e0b2e579b1fd423d 0370a16f70a8a8a0a9afc5c0f3b9aae5d02b9bcf9f3351eb6cba0df8490e54ed2d 02a51147c9e3a554ed35e20cc5ca0fef20e47ae976cfe06a594e135e416bb05e32 3 OP_CHECKMULTISIG',
141
+ '1 027d222586a44cc5d3654748d92de6b4f96050fbdb21b756c5c0d79d1addcb5e31 0374ba6f6eb2edefa8e183ddf5bde4cfd73e929d983856bf6daf0bac430e57fb85 02a51147c9e3a554ed35e20cc5ca0fef20e47ae976cfe06a594e135e416bb05e32 3 OP_CHECKMULTISIG',
142
+ '1 037d222586a44cc5d365474fd37fe2b8fb7e50fbc46cac57c493c6801d91ca45f6 0274be6e22bbacf2b2a880c7bba8e58cce2d91de942556eb61b71bbb5e1356e617 02a51147c9e3a554ed35e20cc5ca0fef20e47ae976cfe06a594e135e416bb05e32 3 OP_CHECKMULTISIG',
143
+ '1 037d222586a44cc5d3650e5f967df5a8f87c1eeec462f872d989de8059c5d648b6 033dbf7371bfa8ede6b68ac6f0afaadbdb33929d94384abe63b35ebe451319e588 02a51147c9e3a554ed35e20cc5ca0fef20e47ae976cfe06a594e135e416bb05e32 3 OP_CHECKMULTISIG',
144
+ '1 027d222586a44cc5d365084fc22de0a3f47703fbd438b14adf939ec510c59e5e12 0269a5666eebbef5a0a780c6e8fcecded132dec9993305a26ab31baa4f0f4da807 02a51147c9e3a554ed35e20cc5ca0fef20e47ae976cfe06a594e135e416bb05e32 3 OP_CHECKMULTISIG',
145
+ '1 027d222586a44cc5d3651059d766fab4e66a15e99723be05c588d7c50dc3cb5e2f 0269ec6863b8a8e4e6ac8ad0feb0a48cfd3093cd9d3351ae68a25eb6450f14fab6 02a51147c9e3a554ed35e20cc5ca0fef20e47ae976cfe06a594e135e416bb05e32 3 OP_CHECKMULTISIG',
146
+ '1 027d222586a44cc5d365024ad37fe7b8f77515bac33eb94bc281d19110ded05ed3 023dad7867eba3efb2e197d1fab0e6d59e2f91ce823f47a761f75eab430f5aed27 02a51147c9e3a554ed35e20cc5ca0fef20e47ae976cfe06a594e135e416bb05e32 3 OP_CHECKMULTISIG',
147
+ '1 037d222586a44cc5d365475adf63f5bff67011f69725b656c589c6900dd8d14359 036eec6963a5a3efb2e184c2f4b5ee8cd33a9ad490224ca563fb1ab159114cfc69 02a51147c9e3a554ed35e20cc5ca0fef20e47ae976cfe06a594e135e416bb05e32 3 OP_CHECKMULTISIG',
148
+ '1 027d222586a44cc5d365024f982dc0b9f03913f5c438f84ad7c0df801dd8df59cd 0374a36422a2a3e3b4a484c7feafaad8cc3e90ce903551a26bb55ebb45124dfb30 02a51147c9e3a554ed35e20cc5ca0fef20e47ae976cfe06a594e135e416bb05e32 3 OP_CHECKMULTISIG',
149
+ '1 037d222586a44cc5d3654b1cda64f9b8e1701efd9738b040918ddb8b10dccb40cd 033dbc7863a8b9e9a5a08994efaeebc2cd3e9dc998394beb77b204bd0a0057ecec 02a51147c9e3a554ed35e20cc5ca0fef20e47ae976cfe06a594e135e416bb05e32 3 OP_CHECKMULTISIG',
150
+ '1 037d222586a44cc5d365475fc379e0b8fb7e50f5d12af851d985929516c2cd44b2 037fa5666bbfb4a0a0ae9794e8b1ebc0d27f9ddc822344a724af0cb9441258eb0d 02a51147c9e3a554ed35e20cc5ca0fef20e47ae976cfe06a594e135e416bb05e32 3 OP_CHECKMULTISIG',
151
+ '1 037d222586a44cc5d3651355d963e7fdb5781efe9738b040c385928c0a91df0dc3 037fbe6563afa8f2e6a28ac7effce3c29e2b96d8d13a4ab877fb11be0a005be11c 02a51147c9e3a554ed35e20cc5ca0fef20e47ae976cfe06a594e135e416bb05e32 3 OP_CHECKMULTISIG',
152
+ '1 037d222586a44cc5d3650b55c274b4a5fa391dfbdc29f84bde8e9f971cc7db5f20 026ea5686eaeedf0a7b888d1f5a8f98cd8308c9d9f394bb961ad1baa59085be4a1 02a51147c9e3a554ed35e20cc5ca0fef20e47ae976cfe06a594e135e416bb05e32 3 OP_CHECKMULTISIG',
153
+ '1 027d222586a44cc5d365021cc568e6a7fc7a15e9996c8f4cc588929111d49e5d3e 0372bf796ba9a4ecafb59c94f4baaadedb299bcf823749e724af16bd0a0f5cedaf 02a51147c9e3a554ed35e20cc5ca0fef20e47ae976cfe06a594e135e416bb05e32 3 OP_CHECKMULTISIG',
154
+ '1 027d222586a44cc5d365031cd062e6f1e16b05e9c36cab55c385d3810a9f9e603b 0378be696aaaa3f4b5e188c1e8a8aacedb7f89dc832f05a462fb0ab04f084ba822 02a51147c9e3a554ed35e20cc5ca0fef20e47ae976cfe06a594e135e416bb05e32 3 OP_CHECKMULTISIG',
155
+ '1 037d222586a44cc5d3650449c579fbbcf06b03b69724b956c28cdb8b1e91ca456c 0278a12a64a4bfa0abae97d1bbb5e4cad12d93dc853f4aa524af16b944414de0ed 02a51147c9e3a554ed35e20cc5ca0fef20e47ae976cfe06a594e135e416bb05e32 3 OP_CHECKMULTISIG',
156
+ '1 027d222586a44cc5d3650245967afba4f97d50f5c324bd57c689c18059dfdb4812 0279e22a43ebaee5b4b584ddf5fcfac9cc3c9bd3853742ae24b418f84c1358fd9a 02a51147c9e3a554ed35e20cc5ca0fef20e47ae976cfe06a594e135e416bb05e32 3 OP_CHECKMULTISIG',
157
+ '1 037d222586a44cc5d365031cdf7eb4b0f67a15eac329bc05d093929017d0c84266 0374a86b60a7a8aee6958dd1e8b9aacfd12c8aced1374baf24ab1fa1470457fcc6 02a51147c9e3a554ed35e20cc5ca0fef20e47ae976cfe06a594e135e416bb05e32 3 OP_CHECKMULTISIG',
158
+ '1 037d222586a44cc5d3654749d86ef1a3e17819f4c325bd569183d38b59d3db0dbb 037cba656bafa8e4e6a88b94ebb9f8dfd131dedf887650b86db519f85a0940fb0e 02a51147c9e3a554ed35e20cc5ca0fef20e47ae976cfe06a594e135e416bb05e32 3 OP_CHECKMULTISIG',
159
+ '1 027d222586a44cc5d3650e5fd761b4b2e06b02ffd92fa1099182c79159dfd10d1a 0270a9696aaaa3e9b5acc5d1e3b5f9d8cd7f8ad2d13b44a061fb0eb9530c5ce606 02a51147c9e3a554ed35e20cc5ca0fef20e47ae976cfe06a594e135e416bb05e32 3 OP_CHECKMULTISIG',
160
+ '1 027d222586a44cc5d365134f9662e2b4e73911bad423b548c48edb8618c5d74244 0273bf2a61a3aceea8a48994ecb5fec4d12a8a9d907651b971a80abd4e4149e9d4 02a51147c9e3a554ed35e20cc5ca0fef20e47ae976cfe06a594e135e416bb05e32 3 OP_CHECKMULTISIG',
161
+ '1 037d222586a44cc5d3651548cf23b486fd7804bade3ff84bd485d6801d91d75e46 023dad6422aea1e5a5b597dbf5b5e98cce3e87d0943851eb77a20dac4f0c19eab3 02a51147c9e3a554ed35e20cc5ca0fef20e47ae976cfe06a594e135e416bb05e32 3 OP_CHECKMULTISIG',
162
+ '1 037d222586a44cc5d365064fd369b4befb3913e8ce3cac4ad692d39511d8dd0d73 036dbe656dadede9a8b291d1fab8aac3d87f8acf842551e724ba12b4451650e621 02a51147c9e3a554ed35e20cc5ca0fef20e47ae976cfe06a594e135e416bb05e32 3 OP_CHECKMULTISIG',
163
+ '1 037d222586a44cc5d365001cd763edf1e16e1fbac025b449d88ed5c509d0cc5903 0274a97922bfa2a0b2b384dae8bde9d89e3b97cf943551a77dfb09b15e0919edcc 02a51147c9e3a554ed35e20cc5ca0fef20e47ae976cfe06a594e135e416bb05e32 3 OP_CHECKMULTISIG',
164
+ '1 037d222586a44cc5d365065fde2dfba5fd7c02bac025ac4dde95c6c50dd9db0db3 0273a96f66ebabefb4e18494efaeffdfca3a9a9d853e4cb960fb0eb9581540a605 02a51147c9e3a554ed35e20cc5ca0fef20e47ae976cfe06a594e135e416bb05e32 3 OP_CHECKMULTISIG',
165
+ '1 037d222586a44cc5d3654768c46cfaa2f47a04f3d822ab05c588d39159d0cc48a5 023daf656fbbb8f4a7b58cdbf5bde6c0c77f97d0812444a870b21db946414de79b 02a51147c9e3a554ed35e20cc5ca0fef20e47ae976cfe06a594e135e416bb05e32 3 OP_CHECKMULTISIG',
166
+ '1 037d222586a44cc5d365474ed37bf1a3e67c50edd839b4419190c08a0dd4dd591a 033dbf6f6ea7a8f2b5e183c6f4b1aacacc3e8bd9dd7644a560fb0cb75f1550e63b 02a51147c9e3a554ed35e20cc5ca0fef20e47ae976cfe06a594e135e416bb05e32 3 OP_CHECKMULTISIG',
167
+ '1 037d222586a44cc5d365021cd37ef7a3fa6e50f7d22fb044df89c1880a91dd4230 0268a06e22aeacf3afad9c94f9b9aac5d32f92d89c334bbf61bf5eac454149fa71 02a51147c9e3a554ed35e20cc5ca0fef20e47ae976cfe06a594e135e416bb05e32 3 OP_CHECKMULTISIG',
168
+ '1 027d222586a44cc5d3650848d36ee0f1f76c09ffc53ff605f88e929111d8cd0d21 036dad7a67b9e1a0b1a4c5c4e9b3fac3cd3adedcd1254aa771af17b744414de797 02a51147c9e3a554ed35e20cc5ca0fef20e47ae976cfe06a594e135e416bb05e32 3 OP_CHECKMULTISIG',
169
+ '1 027d222586a44cc5d3654748de68b4b5fa6c12f6d261ab55d48ed68c17d69e5d8c 026fa3686eaea0a0b3b28cdafcfceb8cce3a9bcfdc224ae674be1baa0a0550fbc3 02a51147c9e3a554ed35e20cc5ca0fef20e47ae976cfe06a594e135e416bb05e32 3 OP_CHECKMULTISIG',
170
+ '1 037d222586a44cc5d365134edf6fe1a5f07d50eede21bd56c581df9559c2db5f85 026ba97822bfa2a0a1a48bd1e9bdfec99e3c91d0812351aa70b211b64b0d19f864 02a51147c9e3a554ed35e20cc5ca0fef20e47ae976cfe06a594e135e416bb05e32 3 OP_CHECKMULTISIG',
171
+ '1 037d222586a44cc5d3651553d96bb4bef33904f2d26cbb4dc38fdc8a15ded944c9 037ead6622a4bfe4a3b3c5dbfdfcfededf318ddc92224ca46aa850f87e095ca8e6 02a51147c9e3a554ed35e20cc5ca0fef20e47ae976cfe06a594e135e416bb05e32 3 OP_CHECKMULTISIG',
172
+ '1 027d222586a44cc5d3651445c579f1bcb57003bac429bb50c38592840a91d242ae 0373ab2a63b8ede8a9af80c7effce4c3da3a8d9d923949a761b80ab15c0455f1a7 02a51147c9e3a554ed35e20cc5ca0fef20e47ae976cfe06a594e135e416bb05e32 3 OP_CHECKMULTISIG',
173
+ '1 037d222586a44cc5d365475fd963e0a3fa7550f7d83ebd05f2b0e7c509dec9487c 026fec7e6aaaa3a0a7af9c94f8b3e5dcdb2d9fc9983842eb63a911ad5a4156ee70 02a51147c9e3a554ed35e20cc5ca0fef20e47ae976cfe06a594e135e416bb05e32 3 OP_CHECKMULTISIG',
174
+ '1 0258222586a44cc5d365475dc279f5b2fe7c02bad923bc40c2ceb2e579b1be2df1 031dcc0a02cbcd80c6c1e5b49bdc8aacbe5ffebdf15625cb04db7ed82a6139888b 02a51147c9e3a554ed35e20cc5ca0fef20e47ae976cfe06a594e135e416bb05e32 3 OP_CHECKMULTISIG',
175
+ 'OP_DUP OP_HASH160 4de50dc01362d6ad9b4365a56167dae8c029bba1 OP_EQUALVERIFY OP_CHECKSIG'
176
+ ])
177
+ end
178
+ end
179
+ end
metadata CHANGED
@@ -1,126 +1,125 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: counterparty_ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
5
- prerelease:
4
+ version: 1.2.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Chris DeRose
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2015-04-21 00:00:00.000000000 Z
11
+ date: 2015-08-01 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: rest-client
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - ">="
20
18
  - !ruby/object:Gem::Version
21
19
  version: '0'
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - ">="
28
25
  - !ruby/object:Gem::Version
29
26
  version: '0'
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: bitcoin-ruby
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ! '>='
31
+ - - ">="
36
32
  - !ruby/object:Gem::Version
37
33
  version: '0'
38
34
  type: :runtime
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ! '>='
38
+ - - ">="
44
39
  - !ruby/object:Gem::Version
45
40
  version: '0'
46
41
  - !ruby/object:Gem::Dependency
47
42
  name: ffi
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
- - - ! '>='
45
+ - - ">="
52
46
  - !ruby/object:Gem::Version
53
47
  version: '0'
54
48
  type: :runtime
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
51
  requirements:
59
- - - ! '>='
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: ruby-rc4
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
60
67
  - !ruby/object:Gem::Version
61
68
  version: '0'
62
69
  - !ruby/object:Gem::Dependency
63
70
  name: rspec
64
71
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
72
  requirements:
67
- - - ! '>='
73
+ - - ">="
68
74
  - !ruby/object:Gem::Version
69
75
  version: '0'
70
76
  type: :development
71
77
  prerelease: false
72
78
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
79
  requirements:
75
- - - ! '>='
80
+ - - ">="
76
81
  - !ruby/object:Gem::Version
77
82
  version: '0'
78
83
  - !ruby/object:Gem::Dependency
79
84
  name: rspec-its
80
85
  requirement: !ruby/object:Gem::Requirement
81
- none: false
82
86
  requirements:
83
- - - ! '>='
87
+ - - ">="
84
88
  - !ruby/object:Gem::Version
85
89
  version: '0'
86
90
  type: :development
87
91
  prerelease: false
88
92
  version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
93
  requirements:
91
- - - ! '>='
94
+ - - ">="
92
95
  - !ruby/object:Gem::Version
93
96
  version: '0'
94
97
  - !ruby/object:Gem::Dependency
95
98
  name: rake
96
99
  requirement: !ruby/object:Gem::Requirement
97
- none: false
98
100
  requirements:
99
- - - ! '>='
101
+ - - ">="
100
102
  - !ruby/object:Gem::Version
101
103
  version: '0'
102
104
  type: :development
103
105
  prerelease: false
104
106
  version_requirements: !ruby/object:Gem::Requirement
105
- none: false
106
107
  requirements:
107
- - - ! '>='
108
+ - - ">="
108
109
  - !ruby/object:Gem::Version
109
110
  version: '0'
110
111
  - !ruby/object:Gem::Dependency
111
112
  name: rdoc
112
113
  requirement: !ruby/object:Gem::Requirement
113
- none: false
114
114
  requirements:
115
- - - ! '>='
115
+ - - ">="
116
116
  - !ruby/object:Gem::Version
117
117
  version: '0'
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
- none: false
122
121
  requirements:
123
- - - ! '>='
122
+ - - ">="
124
123
  - !ruby/object:Gem::Version
125
124
  version: '0'
126
125
  description: This gem is designed to abstract communications with the counterpartyd
@@ -131,7 +130,7 @@ executables: []
131
130
  extensions: []
132
131
  extra_rdoc_files: []
133
132
  files:
134
- - .gitignore
133
+ - ".gitignore"
135
134
  - Gemfile
136
135
  - Gemfile.lock
137
136
  - README.md
@@ -142,6 +141,8 @@ files:
142
141
  - lib/counterparty/raw_tx.rb
143
142
  - lib/counterparty/resource.rb
144
143
  - lib/counterparty/resources.rb
144
+ - lib/counterparty/tx_decode.rb
145
+ - lib/counterparty/tx_encode.rb
145
146
  - lib/counterparty/version.rb
146
147
  - lib/counterparty_ruby.rb
147
148
  - spec/blockr_io_spec.rb
@@ -152,30 +153,31 @@ files:
152
153
  - spec/resource_create_spec.rb
153
154
  - spec/resource_read_spec.rb
154
155
  - spec/spec_helper.rb
156
+ - spec/tx_decode_spec.rb
157
+ - spec/tx_encode_spec.rb
155
158
  homepage: https://github.com/brighton36/counterparty_ruby
156
159
  licenses:
157
160
  - LGPL
161
+ metadata: {}
158
162
  post_install_message:
159
163
  rdoc_options: []
160
164
  require_paths:
161
165
  - lib
162
166
  required_ruby_version: !ruby/object:Gem::Requirement
163
- none: false
164
167
  requirements:
165
- - - ! '>='
168
+ - - ">="
166
169
  - !ruby/object:Gem::Version
167
170
  version: '1.9'
168
171
  required_rubygems_version: !ruby/object:Gem::Requirement
169
- none: false
170
172
  requirements:
171
- - - ! '>='
173
+ - - ">="
172
174
  - !ruby/object:Gem::Version
173
175
  version: '0'
174
176
  requirements: []
175
177
  rubyforge_project:
176
- rubygems_version: 1.8.23
178
+ rubygems_version: 2.4.6
177
179
  signing_key:
178
- specification_version: 3
180
+ specification_version: 4
179
181
  summary: An ActiveRecord-esque abstraction of the Counterparty API
180
182
  test_files:
181
183
  - spec/blockr_io_spec.rb
@@ -186,3 +188,5 @@ test_files:
186
188
  - spec/resource_create_spec.rb
187
189
  - spec/resource_read_spec.rb
188
190
  - spec/spec_helper.rb
191
+ - spec/tx_decode_spec.rb
192
+ - spec/tx_encode_spec.rb