dropzone_ruby 0.1

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.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -0
  3. data/Drop Zone - An Anonymous Peer-To-Peer Local Contraband Marketplace.pdf +0 -0
  4. data/Gemfile +3 -0
  5. data/Gemfile.lock +69 -0
  6. data/README.md +62 -0
  7. data/bin/dropzone +487 -0
  8. data/dropzone-screenshot.jpg +0 -0
  9. data/dropzone_ruby.gemspec +31 -0
  10. data/lib/blockrio_ext.rb +52 -0
  11. data/lib/dropzone/buyer.rb +21 -0
  12. data/lib/dropzone/command.rb +488 -0
  13. data/lib/dropzone/communication.rb +43 -0
  14. data/lib/dropzone/connection.rb +312 -0
  15. data/lib/dropzone/invoice.rb +23 -0
  16. data/lib/dropzone/item.rb +160 -0
  17. data/lib/dropzone/listing.rb +64 -0
  18. data/lib/dropzone/message_base.rb +178 -0
  19. data/lib/dropzone/payment.rb +36 -0
  20. data/lib/dropzone/profile.rb +86 -0
  21. data/lib/dropzone/record_base.rb +34 -0
  22. data/lib/dropzone/seller.rb +21 -0
  23. data/lib/dropzone/session.rb +161 -0
  24. data/lib/dropzone/state_accumulator.rb +39 -0
  25. data/lib/dropzone/version.rb +4 -0
  26. data/lib/dropzone_ruby.rb +14 -0
  27. data/lib/veto_checks.rb +74 -0
  28. data/spec/bitcoin_spec.rb +115 -0
  29. data/spec/buyer_profile_spec.rb +279 -0
  30. data/spec/buyer_spec.rb +109 -0
  31. data/spec/command_spec.rb +353 -0
  32. data/spec/config.yml +5 -0
  33. data/spec/invoice_spec.rb +129 -0
  34. data/spec/item_spec.rb +294 -0
  35. data/spec/lib/fake_connection.rb +97 -0
  36. data/spec/listing_spec.rb +150 -0
  37. data/spec/payment_spec.rb +152 -0
  38. data/spec/seller_profile_spec.rb +290 -0
  39. data/spec/seller_spec.rb +120 -0
  40. data/spec/session_spec.rb +303 -0
  41. data/spec/sham/buyer.rb +5 -0
  42. data/spec/sham/invoice.rb +5 -0
  43. data/spec/sham/item.rb +8 -0
  44. data/spec/sham/payment.rb +13 -0
  45. data/spec/sham/seller.rb +7 -0
  46. data/spec/spec_helper.rb +49 -0
  47. metadata +267 -0
@@ -0,0 +1,109 @@
1
+ #encoding: utf-8
2
+ require_relative 'spec_helper'
3
+ require_relative 'sham/buyer'
4
+
5
+ describe Dropzone::Buyer do
6
+ include_context 'globals'
7
+
8
+ describe "defaults" do
9
+ it "has accessors" do
10
+ buyer = Dropzone::Buyer.sham!(:build)
11
+
12
+ expect(buyer.description).to eq("abc")
13
+ expect(buyer.alias).to eq("Satoshi")
14
+ expect(buyer.transfer_pkey).to be_nil
15
+ expect(buyer.receiver_addr).to eq(test_pubkey)
16
+ expect(buyer.sender_addr).to eq(nil)
17
+ end
18
+ end
19
+
20
+ describe "serialization" do
21
+ it "serializes to_transaction" do
22
+ expect(Dropzone::Buyer.sham!.to_transaction).to eq({
23
+ tip: 20000,
24
+ receiver_addr: test_pubkey,
25
+ data: "BYUPDT\u0001d\u0003abc\u0001a\aSatoshi".force_encoding('ASCII-8BIT') })
26
+ end
27
+ end
28
+
29
+ describe "database" do
30
+ after{ clear_blockchain! }
31
+
32
+ it ".save() and .find()" do
33
+ buyer = Dropzone::Buyer.sham!(:build).save!(test_privkey)
34
+ expect(buyer).to be_kind_of(String)
35
+
36
+ buyer = Dropzone::Buyer.find buyer
37
+ expect(buyer.description).to eq("abc")
38
+ expect(buyer.alias).to eq("Satoshi")
39
+ expect(buyer.transfer_pkey).to be_nil
40
+ expect(buyer.receiver_addr).to eq(test_pubkey)
41
+ expect(buyer.sender_addr).to eq(test_pubkey)
42
+ end
43
+ end
44
+
45
+ describe "validations" do
46
+ it "validates default build" do
47
+ expect(Dropzone::Buyer.sham!(:build).valid?).to eq(true)
48
+ end
49
+
50
+ it "validates minimal buyer" do
51
+ buyer = Dropzone::Buyer.new receiver_addr: test_pubkey
52
+
53
+ expect(buyer.valid?).to eq(true)
54
+ end
55
+
56
+ it "validates output address must be present" do
57
+ buyer = Dropzone::Buyer.sham! receiver_addr: nil
58
+
59
+ expect(buyer.valid?).to eq(false)
60
+ expect(buyer.errors.count).to eq(1)
61
+ expect(buyer.errors.on(:receiver_addr)).to eq(['is not present'])
62
+ end
63
+
64
+ it "description must be string" do
65
+ buyer = Dropzone::Buyer.sham! description: 1
66
+
67
+ expect(buyer.valid?).to eq(false)
68
+ expect(buyer.errors.count).to eq(1)
69
+ expect(buyer.errors.on(:description)).to eq(['is not a string'])
70
+ end
71
+
72
+ it "alias must be string" do
73
+ buyer = Dropzone::Buyer.sham! alias: 1
74
+
75
+ expect(buyer.valid?).to eq(false)
76
+ expect(buyer.errors.count).to eq(1)
77
+ expect(buyer.errors.on(:alias)).to eq(['is not a string'])
78
+ end
79
+
80
+ it "transfer_pkey must be pkey" do
81
+ buyer = Dropzone::Buyer.sham! transfer_pkey: 'bad-key'
82
+
83
+ expect(buyer.valid?).to eq(false)
84
+ expect(buyer.errors.count).to eq(2)
85
+ expect(buyer.errors.on(:transfer_pkey)).to eq(['does not match receiver_addr',
86
+ 'is not a public key' ])
87
+ end
88
+
89
+ it "transfer_pkey must be receiver_addr" do
90
+ buyer = Dropzone::Buyer.sham! transfer_pkey: TESTER2_PUBLIC_KEY
91
+
92
+ expect(buyer.valid?).to eq(false)
93
+ expect(buyer.errors.count).to eq(1)
94
+ expect(buyer.errors.on(:transfer_pkey)).to eq(['does not match receiver_addr'])
95
+ end
96
+
97
+ it "declaration must be addressed to self" do
98
+ id = Dropzone::Buyer.sham!(receiver_addr: TESTER2_PUBLIC_KEY).save! test_privkey
99
+
100
+ buyer = Dropzone::Buyer.find id
101
+
102
+ expect(buyer.valid?).to eq(false)
103
+ expect(buyer.errors.count).to eq(1)
104
+ expect(buyer.errors.on(:receiver_addr)).to eq(['does not match sender_addr'])
105
+ end
106
+ end
107
+
108
+
109
+ end
@@ -0,0 +1,353 @@
1
+ #encoding: utf-8
2
+ require_relative 'spec_helper'
3
+ require_relative '../lib/dropzone/command'
4
+
5
+ class Hash
6
+ alias :__hash__ :to_h
7
+ end
8
+
9
+ describe DropZoneCommand do
10
+ include_context 'globals'
11
+
12
+ before(:all) do
13
+ clear_blockchain!
14
+
15
+ # This allows us to preserve the transaction ids regardless of what tests
16
+ # ran before us.
17
+ db = FakeBitcoinConnection::DB.execute(
18
+ "UPDATE SQLITE_SEQUENCE SET SEQ=0 WHERE NAME='transactions';" )
19
+ end
20
+
21
+ def to_out(string)
22
+ string.strip.gsub(/^[ ]+/,'')+"\n"
23
+ end
24
+
25
+ it "creates buyers" do
26
+ expect{ DropZoneCommand.new(true).profile_buyer_create(
27
+ [test_privkey],
28
+ alias: "Miracle Max",
29
+ description: "First Buyer on DropZone"
30
+ )}.to output(to_out(<<-eos)).to_stdout
31
+ +-------------------------------------------+
32
+ | Buyer: mi37WkBomHJpUghCn7Vgh3ah33h6L9Nkqw |
33
+ +-------------------------------------------+
34
+ | alias : Miracle Max |
35
+ | description: First Buyer on DropZone |
36
+ +-------------------------------------------+
37
+ | Tx: 1 |
38
+ +-------------------------------------------+
39
+ eos
40
+
41
+ expect{ DropZoneCommand.new(true).profile_buyer_show(
42
+ [test_pubkey], {}
43
+ )}.to output(to_out(<<-eos)).to_stdout
44
+ +-------------------------------------------+
45
+ | Buyer: mi37WkBomHJpUghCn7Vgh3ah33h6L9Nkqw |
46
+ +-------------------------------------------+
47
+ | alias : Miracle Max |
48
+ | description: First Buyer on DropZone |
49
+ +-------------------------------------------+
50
+ eos
51
+ end
52
+
53
+ it "creates sellers" do
54
+ expect{ DropZoneCommand.new(true).profile_seller_create(
55
+ [TESTER2_PRIVATE_KEY],
56
+ alias: "Miracle Max",
57
+ description: "First Seller on DropZone",
58
+ communications_pkey: TESTER2_PUBLIC_KEY
59
+ )}.to output(to_out(<<-eos)).to_stdout
60
+ +---------------------------------------------------------+
61
+ | Seller: mqVRfjepJTxxoDgDt892tCybhmjfKCFNyp |
62
+ +---------------------------------------------------------+
63
+ | alias : Miracle Max |
64
+ | description : First Seller on DropZone |
65
+ | communications_pkey: mqVRfjepJTxxoDgDt892tCybhmjfKCFNyp |
66
+ +---------------------------------------------------------+
67
+ | Tx: 2 |
68
+ +---------------------------------------------------------+
69
+ eos
70
+
71
+ expect{ DropZoneCommand.new(true).profile_seller_show(
72
+ [TESTER2_PUBLIC_KEY], {}
73
+ )}.to output(to_out(<<-eos)).to_stdout
74
+ +---------------------------------------------------------+
75
+ | Seller: mqVRfjepJTxxoDgDt892tCybhmjfKCFNyp |
76
+ +---------------------------------------------------------+
77
+ | alias : Miracle Max |
78
+ | description : First Seller on DropZone |
79
+ | communications_pkey: mqVRfjepJTxxoDgDt892tCybhmjfKCFNyp |
80
+ +---------------------------------------------------------+
81
+ eos
82
+ end
83
+
84
+ it "creates listings" do
85
+ expect{ DropZoneCommand.new(true).listing_create(
86
+ [TESTER2_PRIVATE_KEY],
87
+ latitude: "51.500782", longitude: "-0.124669", radius: 1000,
88
+ price_currency: 'USD', price_in_units: 100,
89
+ description: "Test Description"
90
+ )}.to output(to_out(<<-eos)).to_stdout
91
+ +---------------------------------------------+
92
+ | Listing: mfZ1415XX782179875331XX1XXXXXgtzWu |
93
+ +---------------------------------------------+
94
+ | latitude : 51.500782 |
95
+ | longitude : -0.124669 |
96
+ | radius : 1000 |
97
+ | price_currency: USD |
98
+ | price_in_units: 100 |
99
+ | description : Test Description |
100
+ +---------------------------------------------+
101
+ | Tx: 3 |
102
+ +---------------------------------------------+
103
+ eos
104
+
105
+ expect{ DropZoneCommand.new(true).listing_show(
106
+ ['3'], {} )}.to output(to_out(<<-eos)).to_stdout
107
+ +----------------------------------------------------+
108
+ | Listing: 3 |
109
+ +----------------------------------------------------+
110
+ | latitude : 51.500782 |
111
+ | longitude : -0.124669 |
112
+ | radius : 1000 |
113
+ | price_currency: USD |
114
+ | price_in_units: 100 |
115
+ | description : Test Description |
116
+ | addr : mqVRfjepJTxxoDgDt892tCybhmjfKCFNyp |
117
+ +----------------------------------------------------+
118
+ eos
119
+ end
120
+
121
+ it "updates listings" do
122
+ expect{ DropZoneCommand.new(true).listing_update(
123
+ [TESTER2_PRIVATE_KEY, '3'],
124
+ description: "Second Description"
125
+ )}.to output(to_out(<<-eos)).to_stdout
126
+ +---------------------------------------------+
127
+ | Listing: mqVRfjepJTxxoDgDt892tCybhmjfKCFNyp |
128
+ +---------------------------------------------+
129
+ | description: Second Description |
130
+ +---------------------------------------------+
131
+ | Tx: 4 |
132
+ +---------------------------------------------+
133
+ eos
134
+
135
+ expect{ DropZoneCommand.new(true).listing_show(
136
+ ['3'], {} )}.to output(to_out(<<-eos)).to_stdout
137
+ +----------------------------------------------------+
138
+ | Listing: 3 |
139
+ +----------------------------------------------------+
140
+ | latitude : 51.500782 |
141
+ | longitude : -0.124669 |
142
+ | radius : 1000 |
143
+ | price_currency: USD |
144
+ | price_in_units: 100 |
145
+ | description : Second Description |
146
+ | addr : mqVRfjepJTxxoDgDt892tCybhmjfKCFNyp |
147
+ +----------------------------------------------------+
148
+ eos
149
+ end
150
+
151
+ it "creates invoices" do
152
+ expect{ DropZoneCommand.new(true).invoice_create(
153
+ [TESTER2_PRIVATE_KEY, test_pubkey],
154
+ amount_due: 50_000_000, expiration_in: 6
155
+ )}.to output(to_out(<<-eos)).to_stdout
156
+ +---------------------------------------------+
157
+ | Invoice: mi37WkBomHJpUghCn7Vgh3ah33h6L9Nkqw |
158
+ +---------------------------------------------+
159
+ | amount_due : 50000000 |
160
+ | expiration_in: 6 |
161
+ +---------------------------------------------+
162
+ | Tx: 5 |
163
+ +---------------------------------------------+
164
+ eos
165
+
166
+ expect{ DropZoneCommand.new(true).invoice_show(
167
+ ['5'], {} )}.to output(to_out(<<-eos)).to_stdout
168
+ +---------------------------------------------------+
169
+ | Invoice: 5 |
170
+ +---------------------------------------------------+
171
+ | amount_due : 50000000 |
172
+ | expiration_in: 6 |
173
+ | sender_addr : mqVRfjepJTxxoDgDt892tCybhmjfKCFNyp |
174
+ | receiver_addr: mi37WkBomHJpUghCn7Vgh3ah33h6L9Nkqw |
175
+ +---------------------------------------------------+
176
+ eos
177
+ end
178
+
179
+ it "creates reviews" do
180
+ expect{ DropZoneCommand.new(true).review_create(
181
+ [test_privkey, '5'],
182
+ description: 'Fair exchange',
183
+ delivery_quality: 8,
184
+ product_quality: 8,
185
+ communications_quality: 4
186
+ )}.to output(to_out(<<-eos)).to_stdout
187
+ +--------------------------------------------+
188
+ | Review: mqVRfjepJTxxoDgDt892tCybhmjfKCFNyp |
189
+ +--------------------------------------------+
190
+ | description : Fair exchange |
191
+ | delivery_quality : 8 |
192
+ | product_quality : 8 |
193
+ | communications_quality: 4 |
194
+ | invoice_txid : 5 |
195
+ +--------------------------------------------+
196
+ | Tx: 6 |
197
+ +--------------------------------------------+
198
+ eos
199
+
200
+ expect{ DropZoneCommand.new(true).review_show(
201
+ ['6'], {} )}.to output(to_out(<<-eos)).to_stdout
202
+ +------------------------------------------------------------+
203
+ | Review: 6 |
204
+ +------------------------------------------------------------+
205
+ | description : Fair exchange |
206
+ | delivery_quality : 8 |
207
+ | product_quality : 8 |
208
+ | communications_quality: 4 |
209
+ | invoice_txid : 5 |
210
+ | sender_addr : mi37WkBomHJpUghCn7Vgh3ah33h6L9Nkqw |
211
+ | receiver_addr : mqVRfjepJTxxoDgDt892tCybhmjfKCFNyp |
212
+ +------------------------------------------------------------+
213
+ eos
214
+ end
215
+
216
+ it "converses" do
217
+ expect{ DropZoneCommand.new(true).communication_new(
218
+ [test_privkey, TESTER2_PUBLIC_KEY], {}
219
+ )}.to output(to_out(<<-eos)).to_stdout
220
+ +---------------------------------------------------+
221
+ | Session: 7 |
222
+ +---------------------------------------------------+
223
+ | sender_addr : mi37WkBomHJpUghCn7Vgh3ah33h6L9Nkqw |
224
+ | receiver_addr: mqVRfjepJTxxoDgDt892tCybhmjfKCFNyp |
225
+ +---------------------------------------------------+
226
+ eos
227
+
228
+ expect{ DropZoneCommand.new(true).communication_list(
229
+ [test_privkey], {}
230
+ )}.to output(to_out(<<-eos)).to_stdout
231
+ +---------------------------------------------------+
232
+ | Session: 7 |
233
+ +---------------------------------------------------+
234
+ | sender_addr : mi37WkBomHJpUghCn7Vgh3ah33h6L9Nkqw |
235
+ | receiver_addr: mqVRfjepJTxxoDgDt892tCybhmjfKCFNyp |
236
+ +---------------------------------------------------+
237
+ eos
238
+
239
+ expect{ DropZoneCommand.new(true).communication_list(
240
+ [TESTER2_PRIVATE_KEY], {}
241
+ )}.to output(to_out(<<-eos)).to_stdout
242
+ +---------------------------------------------------+
243
+ | Session: 7 |
244
+ +---------------------------------------------------+
245
+ | sender_addr : mi37WkBomHJpUghCn7Vgh3ah33h6L9Nkqw |
246
+ | receiver_addr: mqVRfjepJTxxoDgDt892tCybhmjfKCFNyp |
247
+ +---------------------------------------------------+
248
+ eos
249
+
250
+ expect{ DropZoneCommand.new(true).communication_say(
251
+ [TESTER2_PRIVATE_KEY, '7', 'Greetings Initiator'], {}
252
+ )}.to output(to_out(<<-eos)).to_stdout
253
+ +-------------------------------------------------+
254
+ | Communication: 9 |
255
+ +-------------------------------------------------+
256
+ | Session : 7 |
257
+ | sender_addr: mqVRfjepJTxxoDgDt892tCybhmjfKCFNyp |
258
+ | message : Greetings Initiator |
259
+ +-------------------------------------------------+
260
+ eos
261
+
262
+ expect{ DropZoneCommand.new(true).communication_say(
263
+ [test_privkey, '7', 'Conversation Initiated'], {}
264
+ )}.to output(to_out(<<-eos)).to_stdout
265
+ +-------------------------------------------------+
266
+ | Communication: 10 |
267
+ +-------------------------------------------------+
268
+ | Session : 7 |
269
+ | sender_addr: mi37WkBomHJpUghCn7Vgh3ah33h6L9Nkqw |
270
+ | message : Conversation Initiated |
271
+ +-------------------------------------------------+
272
+ eos
273
+
274
+ expect{ DropZoneCommand.new(true).communication_show(
275
+ [test_privkey, '7'], {}
276
+ )}.to output(to_out(<<-eos)).to_stdout
277
+ +------------------------------------------------------------+
278
+ | Communication: 7 |
279
+ +------------------------------------------------------------+
280
+ | mi37WkBomHJpUghCn7Vgh3ah33h6L9Nkqw: Conversation Initiated |
281
+ | mqVRfjepJTxxoDgDt892tCybhmjfKCFNyp: Greetings Initiator |
282
+ +------------------------------------------------------------+
283
+ eos
284
+
285
+ expect{ DropZoneCommand.new(true).communication_show(
286
+ [TESTER2_PRIVATE_KEY, '7'], {}
287
+ )}.to output(to_out(<<-eos)).to_stdout
288
+ +------------------------------------------------------------+
289
+ | Communication: 7 |
290
+ +------------------------------------------------------------+
291
+ | mi37WkBomHJpUghCn7Vgh3ah33h6L9Nkqw: Conversation Initiated |
292
+ | mqVRfjepJTxxoDgDt892tCybhmjfKCFNyp: Greetings Initiator |
293
+ +------------------------------------------------------------+
294
+ eos
295
+ end
296
+
297
+ it "wraps exceedingly long table values" do
298
+ abstract = (<<-eos).tr("\n", " ")
299
+ Abstract. Drop Zone is a solution to the problem of restricted sales in censored markets.
300
+ The proposal is for the design of a protocol and reference client that encodes the location
301
+ and a brief description of a good onto The Blockchain. Those wishing to purchase the
302
+ good can search for items within a user-requested radius. Sellers list a good as available
303
+ within a geographic region, subject to some degree of precision, for the purpose of
304
+ obfuscating their precise location. Goods are announced next to an expiration, a hashtag,
305
+ and if space permits, a description. Once a buyer finds a good in a defined relative
306
+ proximity, a secure communication channel is opened between the parties on the Bitcoin
307
+ test network ("testnet"). Once negotiations are complete, the buyer sends payment to the
308
+ seller via the address listed on the Bitcoin mainnet. This spend action establishes
309
+ reputation for the buyer, and potentially for the seller. Once paid, the seller is to furnish
310
+ the exact GPS coordinates of the good to the buyer (alongside a small note such as
311
+ "Check in the crevice of the tree"). When the buyer successfully picks up the item at the
312
+ specified location, the buyer then issues a receipt with a note by spending flake to the
313
+ address of the original post. In this way, sellers receive a reputation score. The solution
314
+ is akin to that of Craigslist.org or Uber, but is distributed and as such provides nearly
315
+ risk-free terms to contraband sellers, and drastically reduced risk to contraband buyers.
316
+ eos
317
+
318
+ expect{ DropZoneCommand.new(true).communication_say(
319
+ [test_privkey, '7', abstract], {}
320
+ )}.to output(to_out(<<-eos)).to_stdout
321
+ +----------------------------------------------------------------------------------+
322
+ | Communication: 11 |
323
+ +----------------------------------------------------------------------------------+
324
+ | Session : 7 |
325
+ | sender_addr: mi37WkBomHJpUghCn7Vgh3ah33h6L9Nkqw |
326
+ | message : Abstract. Drop Zone is a solution to the problem of restricted |
327
+ | : sales in censored markets. The proposal is for the design of a |
328
+ | : protocol and reference client that encodes the location and a |
329
+ | : brief description of a good onto The Blockchain. Those wishing to |
330
+ | : purchase the good can search for items within a user-requested |
331
+ | : radius. Sellers list a good as available within a geographic |
332
+ | : region, subject to some degree of precision, for the purpose of |
333
+ | : obfuscating their precise location. Goods are announced next to an |
334
+ | : expiration, a hashtag, and if space permits, a description. Once a |
335
+ | : buyer finds a good in a defined relative proximity, a secure |
336
+ | : communication channel is opened between the parties on the Bitcoin |
337
+ | : test network ("testnet"). Once negotiations are complete, the |
338
+ | : buyer sends payment to the seller via the address listed on the |
339
+ | : Bitcoin mainnet. This spend action establishes reputation for the |
340
+ | : buyer, and potentially for the seller. Once paid, the seller is to |
341
+ | : furnish the exact GPS coordinates of the good to the buyer |
342
+ | : (alongside a small note such as "Check in the crevice of the |
343
+ | : tree"). When the buyer successfully picks up the item at the |
344
+ | : specified location, the buyer then issues a receipt with a note by |
345
+ | : spending flake to the address of the original post. In this way, |
346
+ | : sellers receive a reputation score. The solution is akin to that |
347
+ | : of Craigslist.org or Uber, but is distributed and as such provides |
348
+ | : nearly risk-free terms to contraband sellers, and drastically |
349
+ | : reduced risk to contraband buyers. |
350
+ +----------------------------------------------------------------------------------+
351
+ eos
352
+ end
353
+ end