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,70 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'rest_client'
|
3
|
+
require 'open-uri'
|
4
|
+
require 'bitcoin'
|
5
|
+
|
6
|
+
require 'counterparty/raw_tx'
|
7
|
+
require 'counterparty/version'
|
8
|
+
require 'counterparty/resource'
|
9
|
+
require 'counterparty/resources'
|
10
|
+
require 'counterparty/connection'
|
11
|
+
|
12
|
+
# The main module, under which all classes in the library are defined.
|
13
|
+
module Counterparty
|
14
|
+
# One XCP, in units of Satoshi
|
15
|
+
ONE_XCP = 100_000_000
|
16
|
+
|
17
|
+
# One BTC, in units of Satoshi
|
18
|
+
ONE_BTC = 100_000_000
|
19
|
+
|
20
|
+
# This exception is typically raised by errors related to the params and/or
|
21
|
+
# request format
|
22
|
+
class JsonResponseError < StandardError; end
|
23
|
+
|
24
|
+
# This exception comes from an error relating to a proper request, but an
|
25
|
+
# inability to complete the request via the counterpartyd api
|
26
|
+
class ResponseError < StandardError
|
27
|
+
attr_reader :data_type
|
28
|
+
attr_reader :data_args
|
29
|
+
attr_reader :data_message
|
30
|
+
attr_reader :code
|
31
|
+
attr_reader :message_class
|
32
|
+
|
33
|
+
def initialize(json)
|
34
|
+
@message_class, @code = json['message'], json['code']
|
35
|
+
|
36
|
+
json['data'].each_pair do |(k,v)|
|
37
|
+
instance_variable_set '@data_%s' % k, v
|
38
|
+
end if json.has_key? 'data'
|
39
|
+
|
40
|
+
super
|
41
|
+
end
|
42
|
+
|
43
|
+
def message
|
44
|
+
'%s: %s' % [@message_class,@data_message]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class << self
|
49
|
+
# Sets/Gets the default connection object
|
50
|
+
attr_writer :connection
|
51
|
+
|
52
|
+
# Returns the current default connection object, or creates a new test-mode
|
53
|
+
# connection, if none has been defined
|
54
|
+
def connection
|
55
|
+
@connection || Connection.new
|
56
|
+
end
|
57
|
+
|
58
|
+
# Establishes the default connection for new objects as being the default
|
59
|
+
# counterparty production mode port/user/ip
|
60
|
+
def production!
|
61
|
+
@connection = Connection.new 4000
|
62
|
+
end
|
63
|
+
|
64
|
+
# Establishes the default connection for new objects as being the default
|
65
|
+
# counterparty test mode port/user/ip
|
66
|
+
def test!
|
67
|
+
@connection = Connection.new
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
data/spec/config.yml
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Counterparty::Connection do
|
4
|
+
describe "#new" do
|
5
|
+
# It should default to the test network parameters
|
6
|
+
subject{Counterparty::Connection.new}
|
7
|
+
|
8
|
+
its(:host){ should eq('localhost') }
|
9
|
+
its(:port){ should eq(14000) }
|
10
|
+
its(:username){ should eq('rpc') }
|
11
|
+
its(:password){ should eq('1234') }
|
12
|
+
its(:api_url){ should eq('http://rpc:1234@localhost:14000/api/') }
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Counterparty::ResponseError do
|
4
|
+
include_context 'globals'
|
5
|
+
|
6
|
+
let(:bad_issuance) do
|
7
|
+
Counterparty::Issuance.new source: source_address,
|
8
|
+
asset: 'THISASSETNAMEISFARTOOLONGANDINVALID',
|
9
|
+
quantity: 1000, description: "my asset is uncool",
|
10
|
+
allow_unconfirmed_inputs: true
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should fail on to_raw_tx" do
|
14
|
+
expect{ bad_issuance.to_raw_tx }.to raise_error Counterparty::ResponseError
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should fail on save!" do
|
18
|
+
expect{ bad_issuance.save! }.to raise_error Counterparty::ResponseError
|
19
|
+
end
|
20
|
+
|
21
|
+
subject do
|
22
|
+
begin
|
23
|
+
bad_issuance.save!
|
24
|
+
rescue => error
|
25
|
+
error
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
its(:data_type) { should eq('AssetNameError') }
|
30
|
+
its(:data_args) { should eq(["long asset names must be numeric"]) }
|
31
|
+
its(:data_message) { should eq("long asset names must be numeric") }
|
32
|
+
its(:code) { should eq(-32000) }
|
33
|
+
its(:message) { should eq("Server error: long asset names must be numeric") }
|
34
|
+
end
|
35
|
+
|
36
|
+
describe Counterparty::JsonResponseError do
|
37
|
+
pending
|
38
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RawTx do
|
4
|
+
describe ".double_sha256" do
|
5
|
+
# http://bitcoin.stackexchange.com/questions/2177/how-to-calculate-a-hash-of-a-tx
|
6
|
+
genesis_block = '01000000010000000000000000000000000000000000000000000'+
|
7
|
+
'000000000000000000000FFFFFFFF4D04FFFF001D0104455468652054696D657320'+
|
8
|
+
'30332F4A616E2F32303039204368616E63656C6C6F72206F6E206272696E6B206F6'+
|
9
|
+
'6207365636F6E64206261696C6F757420666F722062616E6B73FFFFFFFF0100F205'+
|
10
|
+
'2A01000000434104678AFDB0FE5548271967F1A67130B7105CD6A828E03909A6796'+
|
11
|
+
'2E0EA1F61DEB649F6BC3F4CEF38C4F35504E51EC112DE5C384DF7BA0B8D578A4C70'+
|
12
|
+
'2B6BF11D5FAC00000000'
|
13
|
+
genesis_double_sha = '4A5E1E4BAAB89F3A32518A88C31BC87F618F76673E2CC77AB2127B7AFDEDA33B'
|
14
|
+
|
15
|
+
pending
|
16
|
+
end
|
17
|
+
|
18
|
+
describe ".nibbles_to_ui" do
|
19
|
+
it "should fail on byte arrays larger than 32 bits" do
|
20
|
+
expect{ RawTx.nibbles_to_ui([1,0,0,0,0]) }.to raise_error(ArgumentError)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Remember that the least significant byte is first here:
|
24
|
+
it ("should convert 0x10 to 1") { expect(RawTx.nibbles_to_ui([1,0])).to eq(1) }
|
25
|
+
it ("should convert 0x01 to 16") { expect(RawTx.nibbles_to_ui([0,1])).to eq(16) }
|
26
|
+
it ("should convert 0xf to 15") { expect(RawTx.nibbles_to_ui([0xf])).to eq(15) }
|
27
|
+
it ("should convert 0x11 to 17") { expect(RawTx.nibbles_to_ui([1,1])).to eq(17) }
|
28
|
+
it ("should convert 0xf1 to 31") { expect(RawTx.nibbles_to_ui([0xf,1])).to eq(31) }
|
29
|
+
it ("should convert 0xff to 255") { expect(RawTx.nibbles_to_ui([0xf,0xf])).to eq(255) }
|
30
|
+
end
|
31
|
+
|
32
|
+
describe ".bytes_to_base64_s" do
|
33
|
+
it "should convert 0x14FB9C03D97E to FPucA91+" do
|
34
|
+
bytes = [0x14, 0xFB, 0x9C, 0x03, 0xD9, 0x7E]
|
35
|
+
expect(RawTx.bytes_to_base64_s bytes).to eq("FPucA9l+")
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should convert 0x14FB9C03D9 to FPucA9k=" do
|
39
|
+
bytes = [0x14, 0xFB, 0x9C, 0x03, 0xD9]
|
40
|
+
expect(RawTx.bytes_to_base64_s bytes).to eq("FPucA9k=")
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should convert 0x14FB9C03 to FPucAw==" do
|
44
|
+
bytes = [0x14, 0xFB, 0x9C, 0x03]
|
45
|
+
expect(RawTx.bytes_to_base64_s bytes).to eq("FPucAw==")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "#to_hash" do
|
50
|
+
# NOTE that these spec values were obtained via:
|
51
|
+
# bitcoind -testnet decoderawtransaction [subject]
|
52
|
+
subject{ RawTx.new(
|
53
|
+
"0100000001ec549bdf53cfb319201d672fc0933500e48505724010dad615a9344b99" +
|
54
|
+
"1721cc010000001976a9148025b288cb325d88bcd7ef5d1ab1f8827778d5ee88acff" +
|
55
|
+
"ffffff03781e0000000000006951210286cdf9ec8742c452bd13299771fe40130124" +
|
56
|
+
"038e2198ffc402204c48cc2d32da21033de0df1555e81783f42e00458d0b542ff293" +
|
57
|
+
"d9d04fbc7704650448ee07728a8a210286b1e4f15de57fd34bde19cf64ad9302e454" +
|
58
|
+
"c4c377677581a951579a124b86e753ae781e00000000000069512102a2cdf9ec8742" +
|
59
|
+
"c452bd2214fe01c9f33b0d0066ed0efb90aa715400038c1c621921034f89bc707587" +
|
60
|
+
"71a393416c21a12b651db3def9851bff574904762b86365caaea210286b1e4f15de5" +
|
61
|
+
"7fd34bde19cf64ad9302e454c4c377677581a951579a124b86e753aec0ba770d0000" +
|
62
|
+
"00001976a9148025b288cb325d88bcd7ef5d1ab1f8827778d5ee88ac00000000").to_hash }
|
63
|
+
|
64
|
+
its(['ver']){should eq(1)}
|
65
|
+
its(['lock_time']){should eq(0)}
|
66
|
+
its(['size']){should eq(338)}
|
67
|
+
its(['vin_sz']){should eq(1)}
|
68
|
+
its(['vout_sz']){should eq(3)}
|
69
|
+
|
70
|
+
its(['vin']) do
|
71
|
+
# If we're testing to base64, the hash would look like:
|
72
|
+
# RawTx.bytes_to_base64_s(out_hash.scan(/../).collect(&:hex))
|
73
|
+
should eq([
|
74
|
+
{ "txid" => "cc2117994b34a915d6da1040720585e4003593c02f671d2019b3cf53df9b54ec",
|
75
|
+
"vout" => 1,
|
76
|
+
"scriptSig" => {
|
77
|
+
"hex" => "76a9148025b288cb325d88bcd7ef5d1ab1f8827778d5ee88ac",
|
78
|
+
"asm" => %w(OP_DUP OP_HASH160
|
79
|
+
8025b288cb325d88bcd7ef5d1ab1f8827778d5ee OP_EQUALVERIFY
|
80
|
+
OP_CHECKSIG).join(' ')
|
81
|
+
}, "sequence" => 4294967295 }])
|
82
|
+
end
|
83
|
+
|
84
|
+
its(['vout']) do
|
85
|
+
should eq( [
|
86
|
+
{ "value" => 0.00007800, "n" => 0,
|
87
|
+
"scriptPubKey" => {
|
88
|
+
"hex" => "51210286cdf9ec8742c452bd13299771fe40130124038e2198ffc40"+
|
89
|
+
"2204c48cc2d32da21033de0df1555e81783f42e00458d0b542ff293d9d04f"+
|
90
|
+
"bc7704650448ee07728a8a210286b1e4f15de57fd34bde19cf64ad9302e45"+
|
91
|
+
"4c4c377677581a951579a124b86e753ae",
|
92
|
+
"asm" => "1 0286cdf9ec8742c452bd13299771fe40130124038e2198ffc402204c48cc2d32da 033de0df1555e81783f42e00458d0b542ff293d9d04fbc7704650448ee07728a8a 0286b1e4f15de57fd34bde19cf64ad9302e454c4c377677581a951579a124b86e7 3 OP_CHECKMULTISIG" }
|
93
|
+
},
|
94
|
+
{ "value" => 0.00007800, "n" => 1,
|
95
|
+
"scriptPubKey" => {
|
96
|
+
"hex" => "512102a2cdf9ec8742c452bd2214fe01c9f33b0d0066ed0efb90aa71"+
|
97
|
+
"5400038c1c621921034f89bc70758771a393416c21a12b651db3def9851bf"+
|
98
|
+
"f574904762b86365caaea210286b1e4f15de57fd34bde19cf64ad9302e454"+
|
99
|
+
"c4c377677581a951579a124b86e753ae",
|
100
|
+
"asm" => "1 02a2cdf9ec8742c452bd2214fe01c9f33b0d0066ed0efb90aa715400038c1c6219 034f89bc70758771a393416c21a12b651db3def9851bff574904762b86365caaea 0286b1e4f15de57fd34bde19cf64ad9302e454c4c377677581a951579a124b86e7 3 OP_CHECKMULTISIG" }
|
101
|
+
},
|
102
|
+
{ "value" => 2.25950400, "n" => 2,
|
103
|
+
"scriptPubKey" => {
|
104
|
+
"hex" => "76a9148025b288cb325d88bcd7ef5d1ab1f8827778d5ee88ac",
|
105
|
+
"asm" => "OP_DUP OP_HASH160 8025b288cb325d88bcd7ef5d1ab1f8827778d5ee OP_EQUALVERIFY OP_CHECKSIG" } } ] )
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
describe("#to_hash coinbase") do
|
110
|
+
|
111
|
+
subject{ RawTx.new(
|
112
|
+
"01000000010000000000000000000000000000000000000000000000000000000000" +
|
113
|
+
"000000ffffffff53038349040d00456c69676975730052d8f72ffabe6d6dd991088d" +
|
114
|
+
"ecd13e658bbecc0b2b4c87306f637828917838c02a5d95d0e1bdff9b040000000000" +
|
115
|
+
"0000002f73733331312f00906b570400000000e4050000ffffffff01bf2087950000" +
|
116
|
+
"00001976a9145399c3093d31e4b0af4be1215d59b857b861ad5d88ac00000000").to_hash }
|
117
|
+
|
118
|
+
pending
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
# NOTE: Most of these examples are from:
|
4
|
+
# https://github.com/CounterpartyXCP/counterpartyd/blob/master/docs/API.rst#id8
|
5
|
+
# The tests have to run in the specified order, as we populate our test account
|
6
|
+
# before running test operations
|
7
|
+
describe Counterparty do
|
8
|
+
include_context 'globals'
|
9
|
+
|
10
|
+
before(:all) { Counterparty.test! }
|
11
|
+
|
12
|
+
# TODO: deprecate?
|
13
|
+
#it "Ensure test account has BTC" do
|
14
|
+
#expect(bitcoin.getreceivedbyaddress(source_address)).to be > 0
|
15
|
+
#end
|
16
|
+
|
17
|
+
describe "Ensure test account has XCP" do
|
18
|
+
subject do
|
19
|
+
Counterparty::Balance.find( filters:
|
20
|
+
{ field: 'address', op: '==', value: source_address}
|
21
|
+
).find{|b| b.asset == 'XCP' }
|
22
|
+
end
|
23
|
+
|
24
|
+
its(:quantity){ should be > Counterparty::ONE_XCP }
|
25
|
+
end
|
26
|
+
|
27
|
+
# Send 1 XCP (specified in satoshis) from one address to another (you must have
|
28
|
+
# the sending address in your bitcoind wallet and it will be broadcast as a
|
29
|
+
# multisig transaction
|
30
|
+
describe "#do_send" do
|
31
|
+
subject do
|
32
|
+
Counterparty::Send.new source: source_address, destination: destination_address,
|
33
|
+
asset: "XCP", quantity: Counterparty::ONE_XCP,
|
34
|
+
allow_unconfirmed_inputs: true
|
35
|
+
end
|
36
|
+
|
37
|
+
its(:to_raw_tx) { should_not be_empty }
|
38
|
+
its(:save!) { should_not be_empty }
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "#do_issuance" do
|
42
|
+
subject do
|
43
|
+
Counterparty::Issuance.new source: source_address, asset: unique_asset_name,
|
44
|
+
quantity: 1000, description: "my asset is cool", divisible: true,
|
45
|
+
allow_unconfirmed_inputs: true
|
46
|
+
end
|
47
|
+
|
48
|
+
its(:to_raw_tx) { should_not be_empty }
|
49
|
+
its(:save!) { should_not be_empty }
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "signed #create_broadcast" do
|
53
|
+
subject do
|
54
|
+
# We want the save(private_key) syntax here
|
55
|
+
Counterparty::Broadcast.new source: source_address, fee_fraction: 0.05,
|
56
|
+
text: "Price of gold, 12AM UTC March1. 1=inc 2=dec/const", value: 2.0,
|
57
|
+
timestamp: 1418926641,
|
58
|
+
allow_unconfirmed_inputs: true
|
59
|
+
end
|
60
|
+
|
61
|
+
its(:to_raw_tx) { should_not be_empty }
|
62
|
+
|
63
|
+
it "should persist using a provided key" do
|
64
|
+
# TODO: Make this work
|
65
|
+
expect(subject.save!(source_privkey)).to_not be_empty
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
# NOTE: Most of these examples are from:
|
4
|
+
# https://github.com/CounterpartyXCP/counterpartyd/blob/master/docs/API.rst#id8
|
5
|
+
describe Counterparty do
|
6
|
+
include_context 'globals'
|
7
|
+
|
8
|
+
before(:all) { Counterparty.production! }
|
9
|
+
|
10
|
+
# Get all burns between blocks 280537 and 280539 where greater than .2 BTC was
|
11
|
+
# burned, sorting by tx_hash (ascending order) With this (and the rest of the
|
12
|
+
# examples below) we use positional arguments, instead of keyword-based arguments
|
13
|
+
describe "#get_burns" do
|
14
|
+
burn_params = {
|
15
|
+
order_by: 'tx_hash',
|
16
|
+
order_dir: 'asc',
|
17
|
+
start_block: 280537,
|
18
|
+
end_block: 280539 }
|
19
|
+
|
20
|
+
subject{ Counterparty::Burn.find burn_params }
|
21
|
+
|
22
|
+
it("should equal get_burns") do
|
23
|
+
expect(subject).to eq(Counterparty.connection.get_burns(burn_params))
|
24
|
+
end
|
25
|
+
|
26
|
+
its('length'){ should eq(10) }
|
27
|
+
its('first') do
|
28
|
+
should eq(Counterparty::Burn.new(
|
29
|
+
tx_index: 1096,
|
30
|
+
source: '1ADpYypUcnbezuuYpCyRCY7G4KD6a9YXiF',
|
31
|
+
block_index: 280537,
|
32
|
+
earned: 129754545455,
|
33
|
+
status: "valid",
|
34
|
+
burned: 100000000,
|
35
|
+
tx_hash: '6e905ec73870d6c6cdc8f4e64767ec41f74c8f07a24cc7c54811134f5b6aa6a7'
|
36
|
+
) )
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Fetch all balances for all assets for both of two addresses, using keyword-
|
41
|
+
# based arguments
|
42
|
+
describe "#get_balances" do
|
43
|
+
balance_params = { filters: {
|
44
|
+
field: 'address', op: '==', value: "14qqz8xpzzEtj6zLs3M1iASP7T4mj687yq" } }
|
45
|
+
|
46
|
+
subject{ Counterparty::Balance.find balance_params }
|
47
|
+
|
48
|
+
it("should equal get_balances") do
|
49
|
+
expect(subject).to eq(Counterparty.connection.get_balances(balance_params))
|
50
|
+
end
|
51
|
+
|
52
|
+
its('length'){ should eq(1) }
|
53
|
+
its('first') do
|
54
|
+
should eq(Counterparty::Balance.new(
|
55
|
+
quantity: 0,
|
56
|
+
asset: "XCP",
|
57
|
+
address: "14qqz8xpzzEtj6zLs3M1iASP7T4mj687yq" ) )
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Fetch all debits for > 2 XCP between blocks 280537 and 280539, sorting the
|
62
|
+
# results by quantity (descending order)
|
63
|
+
describe "#get_debits" do
|
64
|
+
debit_params = {
|
65
|
+
filters: [
|
66
|
+
{field: 'asset', op: '==', value: "XCP"},
|
67
|
+
{field: 'quantity', op: '>', value: 200000000}
|
68
|
+
],
|
69
|
+
filterop: 'AND',
|
70
|
+
order_by: 'quantity',
|
71
|
+
order_dir: 'desc'}
|
72
|
+
|
73
|
+
subject{ Counterparty::Debit.find debit_params }
|
74
|
+
|
75
|
+
it("should equal get_debits") do
|
76
|
+
expect(subject).to eq(Counterparty.connection.get_debits(debit_params))
|
77
|
+
end
|
78
|
+
|
79
|
+
its('length'){ should eq(1000) }
|
80
|
+
its('first') do
|
81
|
+
should eq(Counterparty::Debit.new(
|
82
|
+
block_index: 318845,
|
83
|
+
asset: "XCP",
|
84
|
+
address: "1FxhdSid1TUfzfTyveMcsUhF3ePjRK6qqa",
|
85
|
+
action: "send",
|
86
|
+
event: "64c26f4dc12fbbdbead62962a9428d4a6b17a44c061d202ff525e2f513cd34e8",
|
87
|
+
quantity: 6184957374430
|
88
|
+
) )
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
$:<< File.join(File.dirname(__FILE__), '..','lib')
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
require 'rspec/its'
|
5
|
+
require 'counterparty_ruby'
|
6
|
+
|
7
|
+
shared_context 'globals' do
|
8
|
+
let(:config) do
|
9
|
+
YAML.load File.open([File.dirname(__FILE__),'config.yml'].join('/')).read
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:source_address) { config['source_address'] }
|
13
|
+
let(:source_privkey) { config['source_privkey'] }
|
14
|
+
let(:destination_address) { config['spend_destination'] }
|
15
|
+
|
16
|
+
# Since asset names have to be unique, we try our best to create a unique
|
17
|
+
# one here. This asset is composed of the timestamp, plus the machine
|
18
|
+
# name we're running on. Be advised this might be a small privacy breach
|
19
|
+
# forsensitive operations.
|
20
|
+
# There might be some collisions here due to my not handling fixed-width
|
21
|
+
# integers greater than 26. I don't think I care about that right now
|
22
|
+
let!(:unique_asset_name) do
|
23
|
+
base26_time = Time.now.strftime('%y %m %d %H %M %S').split(' ').collect{|c| c.to_i.to_s(26)}
|
24
|
+
alpha_encode = base26_time.join.tr((('0'..'9').to_a+('a'..'q').to_a).join, ('A'..'Z').to_a.join)
|
25
|
+
|
26
|
+
[alpha_encode,`hostname`.upcase.tr('^A-Z','')].join[0...12]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
metadata
ADDED
@@ -0,0 +1,185 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: counterparty_ruby
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.9.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Chris DeRose
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2015-01-07 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rest_client
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: bitcoin-ruby
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: ffi
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rspec
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: rspec-its
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: rake
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: rdoc
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
description: This gem is designed to abstract communications with the counterpartyd
|
127
|
+
api server in an ActiveRecord-esque object model
|
128
|
+
email:
|
129
|
+
- chris@chrisderose.com
|
130
|
+
executables: []
|
131
|
+
extensions: []
|
132
|
+
extra_rdoc_files: []
|
133
|
+
files:
|
134
|
+
- .gitignore
|
135
|
+
- Gemfile
|
136
|
+
- Gemfile.lock
|
137
|
+
- README.md
|
138
|
+
- Rakefile
|
139
|
+
- counterparty_ruby.gemspec
|
140
|
+
- lib/counterparty/connection.rb
|
141
|
+
- lib/counterparty/raw_tx.rb
|
142
|
+
- lib/counterparty/resource.rb
|
143
|
+
- lib/counterparty/resources.rb
|
144
|
+
- lib/counterparty/version.rb
|
145
|
+
- lib/counterparty_ruby.rb
|
146
|
+
- spec/config.yml
|
147
|
+
- spec/connection_spec.rb
|
148
|
+
- spec/exceptions_spec.rb
|
149
|
+
- spec/rawtx_decode_spec.rb
|
150
|
+
- spec/resource_create_spec.rb
|
151
|
+
- spec/resource_read_spec.rb
|
152
|
+
- spec/spec_helper.rb
|
153
|
+
homepage: https://github.com/brighton36/counterparty_ruby
|
154
|
+
licenses:
|
155
|
+
- LGPL
|
156
|
+
post_install_message:
|
157
|
+
rdoc_options: []
|
158
|
+
require_paths:
|
159
|
+
- lib
|
160
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
161
|
+
none: false
|
162
|
+
requirements:
|
163
|
+
- - ! '>='
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: '1.9'
|
166
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
167
|
+
none: false
|
168
|
+
requirements:
|
169
|
+
- - ! '>='
|
170
|
+
- !ruby/object:Gem::Version
|
171
|
+
version: '0'
|
172
|
+
requirements: []
|
173
|
+
rubyforge_project:
|
174
|
+
rubygems_version: 1.8.23
|
175
|
+
signing_key:
|
176
|
+
specification_version: 3
|
177
|
+
summary: An ActiveRecord-esque abstraction of the Counterparty API
|
178
|
+
test_files:
|
179
|
+
- spec/config.yml
|
180
|
+
- spec/connection_spec.rb
|
181
|
+
- spec/exceptions_spec.rb
|
182
|
+
- spec/rawtx_decode_spec.rb
|
183
|
+
- spec/resource_create_spec.rb
|
184
|
+
- spec/resource_read_spec.rb
|
185
|
+
- spec/spec_helper.rb
|