counterparty_ruby 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,179 @@
1
+ module Counterparty
2
+ # A base class for the purpose of extending by api result hashes
3
+ class CounterResource
4
+ # This is mostly used by the eq operation and indicates the
5
+ # attributes that this resource has
6
+ attr_accessor :result_attributes # :nodoc:
7
+
8
+ # encoding (string): The encoding method to use
9
+ attr_accessor :encoding
10
+
11
+ # pubkey (string): The pubkey hex string. Required if multisig transaction
12
+ # encoding is specified for a key external to counterpartyd's local wallet.
13
+ attr_accessor :pubkey
14
+
15
+ # allow_unconfirmed_inputs (boolean): Set to true to allow this transaction
16
+ # to utilize unconfirmed UTXOs as inputs.
17
+ attr_accessor :allow_unconfirmed_inputs
18
+
19
+ # fee (integer): If you'd like to specify a custom miners' fee, specify it
20
+ # here (in satoshi). Leave as default for counterpartyd to automatically
21
+ # choose.
22
+ attr_accessor :fee
23
+
24
+ # fee_per_kb (integer): The fee per kilobyte of transaction data constant
25
+ # that counterpartyd uses when deciding on the dynamic fee to use
26
+ # (in satoshi). Leave as default unless you know what you're doing.
27
+ attr_accessor :fee_per_kb
28
+
29
+ def initialize(attrs={})
30
+ @result_attributes = attrs.keys.sort.collect(&:to_sym)
31
+ attrs.each{|k,v| instance_variable_set '@%s' % k, v}
32
+ end
33
+
34
+ # Just a simple compare. No need to get crazy
35
+ def ==(b) # :nodoc:
36
+ ( b.respond_to?(:result_attributes) &&
37
+ result_attributes == b.result_attributes &&
38
+ @result_attributes.all?{ |k| send(k) == b.send(k) } )
39
+ end
40
+
41
+ # This method returns the unsigned raw create transaction string. hex
42
+ # encoded (i.e. the same format that bitcoind returns with its raw
43
+ # transaction API calls).
44
+ def to_raw_tx
45
+ connection.request self.class.to_create_request, to_params
46
+ end
47
+
48
+ # Given the provided private key, this method returns a signed transaction
49
+ # suitable for broadcasting on the network.
50
+ #
51
+ # NOTE: This method communicates your private key to the counterpartyd
52
+ # server, which might not be what you want!
53
+ def to_signed_tx(private_key)
54
+ sign_tx to_raw_tx, private_key
55
+ end
56
+
57
+ # Commit this object to the blockchain. If a private key is passed, the
58
+ # transaction is signed using this key via a create_ call and a subsequent
59
+ # sign_tx call.
60
+ # NOTE: This method communicates your private key to the counterpartyd
61
+ # server, which might not be what you want!
62
+ def save!(private_key = nil)
63
+ (private_key) ?
64
+ connection.broadcast_tx( to_signed_tx(private_key) ) :
65
+ connection.request(self.class.to_do_request, to_params)
66
+ end
67
+
68
+ private
69
+
70
+ # Currently this is communicating the request to the backend. This method
71
+ # is a stub for when we decide in the future to Use the bitcoin-client gem
72
+ # to perform signatures
73
+ def sign_tx(raw_tx, pkey_wif)
74
+ key = ::Bitcoin.open_key pkey_wif
75
+ raw_tx_hash = RawTx.new(raw_tx).to_hash
76
+
77
+ prev_hash = raw_tx_hash['vin'][0]['txid']
78
+ prior_tx_json = open("http://test.webbtc.com/tx/#{prev_hash}.json").read
79
+ puts prior_tx_json.inspect
80
+ prev_tx = Bitcoin::P::Tx.from_json(prior_tx_json.to_s)
81
+
82
+
83
+ puts "HERE"
84
+ signed_tx = Bitcoin::Protocol::Tx.new
85
+ signed_tx.ver = raw_tx_hash['ver']
86
+ signed_tx.lock = raw_tx_hash['lock_time']
87
+
88
+ tx_in= TxInBuilder.new
89
+ tx_in.prev_out prev_tx
90
+ tx_in.prev_out_index 0
91
+ tx_in.signature_key key
92
+
93
+ signed_tx.add_in tx_in.tx
94
+
95
+ # Here's how we put them in the raw
96
+ # @block.tx << tx
97
+
98
+
99
+ # We need to compare against
100
+ # Primarily: http://www.righto.com/2014/02/bitcoins-hard-way-using-raw-bitcoin.html
101
+ # With Some of this: https://bitcoin.org/en/developer-reference#signrawtransaction
102
+ =begin
103
+ def sign(tx, i, priv, hashcode=SIGHASH_ALL):
104
+ i = int(i)
105
+ if not re.match('^[0-9a-fA-F]*$', tx):
106
+ return binascii.unhexlify(sign(binascii.hexlify(tx), i, priv))
107
+ if len(priv) <= 33:
108
+ priv = binascii.hexlify(priv)
109
+ pub = privkey_to_pubkey(priv)
110
+ address = pubkey_to_address(pub)
111
+ signing_tx = signature_form(tx, i, mk_pubkey_script(address), hashcode)
112
+ sig = ecdsa_tx_sign(signing_tx, priv, hashcode)
113
+ txobj = deserialize(tx)
114
+ txobj["ins"][i]["script"] = serialize_script([sig, pub])
115
+ return serialize(txobj)
116
+ =end
117
+
118
+
119
+ scriptSig = Bitcoin.sign_data(key,
120
+ raw_tx_hash["in"][0]["scriptSig"] ).unpack('h*').first
121
+ # TODO: We may have to iterate over each input
122
+ raw_tx_hash["in"][0]["scriptSig"] = scriptSig
123
+
124
+ ret = Bitcoin::Protocol::Tx.from_hash(raw_tx_hash).to_payload.unpack('h*').first
125
+
126
+ ret
127
+ end
128
+
129
+ def connection
130
+ self.class.connection
131
+ end
132
+
133
+ # This serializes self into a hash suitable for transmission via json
134
+ def to_params
135
+ Hash[* @result_attributes.collect{|k|
136
+ v = self.send(k)
137
+ (v) ? [k,self.send(k)] : nil
138
+ }.compact.flatten]
139
+ end
140
+
141
+ class << self
142
+ # The base connection object for this class
143
+ attr_writer :connection
144
+
145
+ # Returns the counterparty-api version of this objects class name
146
+ def api_name
147
+ to_s.split('::').last.gsub(/[^\A]([A-Z])/, '_\\1').downcase
148
+ end
149
+
150
+ # Returns the currently assigned connection object, or if one hasn't
151
+ # been set, the default specified in the Counterparty module
152
+ def connection
153
+ @connection || Counterparty.connection
154
+ end
155
+
156
+ # Returns the method name of a do_* request for this resource
157
+ def to_do_request
158
+ 'do_%s' % api_name
159
+ end
160
+
161
+ # Returns the method name of a create_* request for this resource
162
+ def to_create_request
163
+ 'create_%s' % api_name
164
+ end
165
+
166
+ # Returns the method name of a get_* request for this resource
167
+ def to_get_request
168
+ 'get_%ss' % api_name
169
+ end
170
+
171
+ # Queries the counterpartyd connection to find matching instances of this
172
+ # resource, given the filters provided in the params
173
+ def find(params)
174
+ connection.request(to_get_request, params).collect{|r| new r}
175
+ end
176
+ end
177
+ end
178
+ end
179
+