counterparty_ruby 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +4 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +46 -0
- data/README.md +197 -0
- data/Rakefile +28 -0
- data/counterparty_ruby.gemspec +26 -0
- data/lib/counterparty/connection.rb +200 -0
- data/lib/counterparty/raw_tx.rb +130 -0
- data/lib/counterparty/resource.rb +179 -0
- data/lib/counterparty/resources.rb +713 -0
- data/lib/counterparty/version.rb +4 -0
- data/lib/counterparty_ruby.rb +70 -0
- data/spec/config.yml +3 -0
- data/spec/connection_spec.rb +14 -0
- data/spec/exceptions_spec.rb +38 -0
- data/spec/rawtx_decode_spec.rb +122 -0
- data/spec/resource_create_spec.rb +69 -0
- data/spec/resource_read_spec.rb +91 -0
- data/spec/spec_helper.rb +29 -0
- metadata +185 -0
@@ -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
|
+
|