dropzone_ruby 0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/Drop Zone - An Anonymous Peer-To-Peer Local Contraband Marketplace.pdf +0 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +69 -0
- data/README.md +62 -0
- data/bin/dropzone +487 -0
- data/dropzone-screenshot.jpg +0 -0
- data/dropzone_ruby.gemspec +31 -0
- data/lib/blockrio_ext.rb +52 -0
- data/lib/dropzone/buyer.rb +21 -0
- data/lib/dropzone/command.rb +488 -0
- data/lib/dropzone/communication.rb +43 -0
- data/lib/dropzone/connection.rb +312 -0
- data/lib/dropzone/invoice.rb +23 -0
- data/lib/dropzone/item.rb +160 -0
- data/lib/dropzone/listing.rb +64 -0
- data/lib/dropzone/message_base.rb +178 -0
- data/lib/dropzone/payment.rb +36 -0
- data/lib/dropzone/profile.rb +86 -0
- data/lib/dropzone/record_base.rb +34 -0
- data/lib/dropzone/seller.rb +21 -0
- data/lib/dropzone/session.rb +161 -0
- data/lib/dropzone/state_accumulator.rb +39 -0
- data/lib/dropzone/version.rb +4 -0
- data/lib/dropzone_ruby.rb +14 -0
- data/lib/veto_checks.rb +74 -0
- data/spec/bitcoin_spec.rb +115 -0
- data/spec/buyer_profile_spec.rb +279 -0
- data/spec/buyer_spec.rb +109 -0
- data/spec/command_spec.rb +353 -0
- data/spec/config.yml +5 -0
- data/spec/invoice_spec.rb +129 -0
- data/spec/item_spec.rb +294 -0
- data/spec/lib/fake_connection.rb +97 -0
- data/spec/listing_spec.rb +150 -0
- data/spec/payment_spec.rb +152 -0
- data/spec/seller_profile_spec.rb +290 -0
- data/spec/seller_spec.rb +120 -0
- data/spec/session_spec.rb +303 -0
- data/spec/sham/buyer.rb +5 -0
- data/spec/sham/invoice.rb +5 -0
- data/spec/sham/item.rb +8 -0
- data/spec/sham/payment.rb +13 -0
- data/spec/sham/seller.rb +7 -0
- data/spec/spec_helper.rb +49 -0
- metadata +267 -0
@@ -0,0 +1,39 @@
|
|
1
|
+
module Dropzone
|
2
|
+
module StateAccumulator
|
3
|
+
# NOTE: This includes only the valid() messages sent/received on this address
|
4
|
+
def messages(options = {})
|
5
|
+
@messages ||= blockchain.messages_by_addr addr,
|
6
|
+
{type: self.class.message_types}.merge(options)
|
7
|
+
end
|
8
|
+
|
9
|
+
def blockchain
|
10
|
+
Dropzone::RecordBase.blockchain
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.included(base)
|
14
|
+
base.extend ClassMethods
|
15
|
+
end
|
16
|
+
|
17
|
+
module ClassMethods
|
18
|
+
def state_attr(*attrs)
|
19
|
+
attr_reader *attrs
|
20
|
+
@state_attributes ||= []
|
21
|
+
@state_attributes += attrs
|
22
|
+
end
|
23
|
+
|
24
|
+
def message_types=(type); @message_types = type; end
|
25
|
+
def message_types; @message_types; end
|
26
|
+
def state_attributes; @state_attributes; end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def attrs_from(message)
|
32
|
+
self.class.state_attributes.each do |attr|
|
33
|
+
value = message.send attr
|
34
|
+
self.instance_variable_set '@%s' % attr, value if value
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'bigdecimal'
|
2
|
+
require 'securerandom'
|
3
|
+
|
4
|
+
require 'veto'
|
5
|
+
require 'bitcoin'
|
6
|
+
require 'counterparty_ruby'
|
7
|
+
|
8
|
+
require 'veto_checks'
|
9
|
+
require 'blockrio_ext'
|
10
|
+
|
11
|
+
%w(connection record_base message_base state_accumulator item invoice payment
|
12
|
+
seller buyer profile listing communication session).each do |resource|
|
13
|
+
require 'dropzone/%s' % resource
|
14
|
+
end
|
data/lib/veto_checks.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
module Veto
|
2
|
+
module AgainstAttributeCco
|
3
|
+
MSG_MISSING_ATTR = "missing required option :attribute"
|
4
|
+
|
5
|
+
def call(cco)
|
6
|
+
raise StandardError, MSG_MISSING_ATTR unless @options[:attribute]
|
7
|
+
|
8
|
+
value = cco.entity.public_send(@attribute_name)
|
9
|
+
value_against = cco.entity.public_send(@options[:attribute])
|
10
|
+
|
11
|
+
check @attribute_name, value, value_against, cco.errors, @options
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class IsStringCheck < AttributeCheck
|
16
|
+
MSG = "is not a string"
|
17
|
+
|
18
|
+
def check(attribute, value, errors, options={})
|
19
|
+
on = options.fetch(:on, attribute)
|
20
|
+
errors.add(on, options[:message] || MSG) unless value.is_a? String
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class IsPkeyCheck < AttributeCheck
|
25
|
+
MSG = "is not a public key"
|
26
|
+
|
27
|
+
def call(cco)
|
28
|
+
@blockchain = cco.entity.blockchain
|
29
|
+
super(cco)
|
30
|
+
end
|
31
|
+
|
32
|
+
def check(attribute, value, errors, options={})
|
33
|
+
on = options.fetch(:on, attribute)
|
34
|
+
unless value == 0 || anynet_valid_address?(value)
|
35
|
+
errors.add(on, options[:message] || MSG)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def anynet_valid_address?(addr)
|
40
|
+
start_network = Bitcoin.network_name
|
41
|
+
|
42
|
+
begin
|
43
|
+
Bitcoin.network = (/\A1/.match addr) ? :bitcoin : :testnet3
|
44
|
+
|
45
|
+
return Bitcoin.valid_address?(addr)
|
46
|
+
ensure
|
47
|
+
Bitcoin.network = start_network
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class EqualsAttributeCheck < AttributeCheck
|
53
|
+
include AgainstAttributeCco
|
54
|
+
|
55
|
+
MSG = "does not match %s"
|
56
|
+
|
57
|
+
def check(attribute, value, against, errors, options={})
|
58
|
+
errors.add(options.fetch(:on, attribute),
|
59
|
+
(options[:message] || MSG) % options[:attribute] ) unless value == against
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class DoesntEqualAttributeCheck < AttributeCheck
|
64
|
+
include AgainstAttributeCco
|
65
|
+
|
66
|
+
MSG = "matches %s"
|
67
|
+
|
68
|
+
def check(attribute, value, against, errors, options={})
|
69
|
+
errors.add(options.fetch(:on, attribute),
|
70
|
+
(options[:message] || MSG) % options[:attribute] ) if value == against
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
require_relative 'spec_helper'
|
3
|
+
require_relative 'sham/item'
|
4
|
+
|
5
|
+
describe Dropzone do
|
6
|
+
describe "scratch" do
|
7
|
+
PRIVATE_KEY_WIF = "92UvdTpmxA6cvD6YeJZSiHW8ff8DsZXL2PHZu9Mg7JY3zbaETJw"
|
8
|
+
# Public Address: mi37WkBomHJpUghCn7Vgh3ah33h6L9Nkqw
|
9
|
+
|
10
|
+
before(:all) do
|
11
|
+
Bitcoin.network = :testnet3
|
12
|
+
TCPSocket::socks_server = "127.0.0.1"
|
13
|
+
TCPSocket::socks_port = 9050
|
14
|
+
# Socksify::debug = true
|
15
|
+
#RestClient.log = Logger.new STDOUT
|
16
|
+
|
17
|
+
connection = Dropzone::BitcoinConnection.new :testnet3
|
18
|
+
Dropzone::RecordBase.blockchain = connection
|
19
|
+
end
|
20
|
+
|
21
|
+
let(:connection){
|
22
|
+
Dropzone::BitcoinConnection.new :testnet3
|
23
|
+
}
|
24
|
+
let(:genesis_intro) {
|
25
|
+
'In the beginning God created the heavens and the earth. Now the earth was formless and empty, darkness was over the surface of the deep, and the Spirit of God was hovering over the waters. And God said, "Let there be light," and there was light. God saw that the light was good, and he separated the light from the darkness. God called the light "day," and the darkness he called "night." And there was evening, and there was morning-the first day. And God said, "Let there be a vault between the waters to separate water from water." So God made the vault and separated the water under the vault from the water above it. And it was so. God called the vault "sky." And there was evening, and there was morning-the second day. And God said, "Let the water under the sky be gathered to one place, and let dry ground appear." And it was so. God called the dry ground "land," and the gathered waters he called "seas." And God saw that it was good. Then God said, "Let the land produce vegetation: seed-bearing plants and trees on the land that bear fruit with seed in it, according to their various kinds." And it was so. The land produced vegetation: plants bearing seed according to their kinds and trees bearing fruit with seed in it according to their kinds. And God saw that it was good. And there was evening, and there was morning-the third day. And God said, "Let there be lights in the vault of the sky to separate the day from the night, and let them serve as signs to mark sacred times, and days and years, and let them be lights in the vault of the sky to give light on the earth." And it was so. God made two great lights-the greater light to govern the day and the lesser light to govern the night. He also made the stars. God set them in the vault of the sky to give light on the earth, to govern the day and the night, and to separate light from darkness. And God saw that it was good. And there was evening, and there was morning-the fourth day.'}
|
26
|
+
|
27
|
+
it "Goes through tor" do
|
28
|
+
ret = RestClient.get 'http://www.ipchicken.com/'
|
29
|
+
parts = /([\d]+\.[\d]+\.[\d]+\.[\d]+)/.match ret
|
30
|
+
puts "Running from:"+parts[1].inspect
|
31
|
+
end
|
32
|
+
|
33
|
+
it "issues a spend" do
|
34
|
+
# let's parse the keys:
|
35
|
+
to = "msj42CCGruhRsFrGATiUuh25dtxYtnpbTx"
|
36
|
+
satoshis = 1_000_000 # 0.01 BTC in satoshis
|
37
|
+
tip = 500_000 # 0.005 BTC
|
38
|
+
|
39
|
+
from_key = Bitcoin::Key.from_base58 PRIVATE_KEY_WIF
|
40
|
+
|
41
|
+
#ret = connection.send_value from_key, to, satoshis, tip
|
42
|
+
#puts "Spend Ret: #{ret.inspect}"
|
43
|
+
end
|
44
|
+
|
45
|
+
it "persists a large item" do
|
46
|
+
Dropzone::MessageBase.blockchain = connection
|
47
|
+
|
48
|
+
item = Dropzone::Item.sham!(:build, description: genesis_intro)
|
49
|
+
#ret = item.save!(PRIVATE_KEY_WIF)
|
50
|
+
#puts ret.inspect
|
51
|
+
end
|
52
|
+
|
53
|
+
it "decodes a large transaction" do
|
54
|
+
Dropzone::Item.blockchain = Dropzone::BitcoinConnection.new :testnet3
|
55
|
+
|
56
|
+
item = Dropzone::Item.find '0b2772eab7823a14fe5d369d3534d4a9d19b19ac0a44855b0aaf9cefcbfe49c7'
|
57
|
+
|
58
|
+
expect(item.description).to eq(genesis_intro)
|
59
|
+
expect(item.price_currency).to eq('BTC')
|
60
|
+
expect(item.price_in_units).to eq(100_000_000)
|
61
|
+
expect(item.expiration_in).to eq(6)
|
62
|
+
expect(item.latitude).to eq(51.500782)
|
63
|
+
expect(item.longitude).to eq(-0.124669)
|
64
|
+
expect(item.radius).to eq(1000)
|
65
|
+
expect(item.receiver_addr).to eq('mfZ1415XX782179875331XX1XXXXXgtzWu')
|
66
|
+
end
|
67
|
+
|
68
|
+
it "enumerates messages by address for a seller" do
|
69
|
+
profile = Dropzone::SellerProfile.new 'mi37WkBomHJpUghCn7Vgh3ah33h6L9Nkqw'
|
70
|
+
|
71
|
+
expect(profile.valid?).to be_truthy
|
72
|
+
expect(profile.description).to eq("Test Description")
|
73
|
+
expect(profile.alias).to eq("Satoshi")
|
74
|
+
expect(profile.communications_pkey).to eq('n3EMs5L3sHcZqRy35cmoPFgw5AzAtWSDUv')
|
75
|
+
expect(profile.addr).to eq('mi37WkBomHJpUghCn7Vgh3ah33h6L9Nkqw')
|
76
|
+
expect(profile.active?).to be_truthy
|
77
|
+
end
|
78
|
+
|
79
|
+
it "enumerates messages by address for a buyer" do
|
80
|
+
profile = Dropzone::BuyerProfile.new 'mqVRfjepJTxxoDgDt892tCybhmjfKCFNyp'
|
81
|
+
expect(profile.valid?).to be_truthy
|
82
|
+
expect(profile.description).to eq("Test Buyer Description")
|
83
|
+
expect(profile.alias).to eq("Test Buyer")
|
84
|
+
expect(profile.addr).to eq('mqVRfjepJTxxoDgDt892tCybhmjfKCFNyp')
|
85
|
+
expect(profile.active?).to be_truthy
|
86
|
+
end
|
87
|
+
|
88
|
+
it "finds invoices and payments" do
|
89
|
+
invoice = Dropzone::Invoice.find '070288a455f14966d77f3877cd21befbd000f23ff3f190e2eb9c1fbbd7d5ac08'
|
90
|
+
|
91
|
+
expect(invoice.expiration_in).to eq(6000)
|
92
|
+
expect(invoice.amount_due).to eq(1000)
|
93
|
+
expect(invoice.receiver_addr).to eq('mqVRfjepJTxxoDgDt892tCybhmjfKCFNyp')
|
94
|
+
expect(invoice.sender_addr).to eq('mi37WkBomHJpUghCn7Vgh3ah33h6L9Nkqw')
|
95
|
+
|
96
|
+
payment = Dropzone::Payment.find 'a2598c76593b17c698e4b58637ae4193a27df4c43b8c3b6d3d1e26cc10602325'
|
97
|
+
|
98
|
+
expect(payment.description).to eq("Fair Exchange")
|
99
|
+
expect(payment.invoice_txid).to be_kind_of(String)
|
100
|
+
expect(payment.delivery_quality).to eq(8)
|
101
|
+
expect(payment.product_quality).to eq(8)
|
102
|
+
expect(payment.communications_quality).to eq(4)
|
103
|
+
expect(payment.sender_addr).to eq('mqVRfjepJTxxoDgDt892tCybhmjfKCFNyp')
|
104
|
+
expect(payment.receiver_addr).to eq('mi37WkBomHJpUghCn7Vgh3ah33h6L9Nkqw')
|
105
|
+
end
|
106
|
+
|
107
|
+
it "Enumerates through listings via Item" do
|
108
|
+
# This is diffucult ATM due to blockchain.info not supporting testnet
|
109
|
+
# and blockr.io's implementation not including all transactions
|
110
|
+
pending
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,279 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
require_relative 'spec_helper'
|
3
|
+
require_relative 'sham/buyer'
|
4
|
+
|
5
|
+
describe Dropzone::BuyerProfile do
|
6
|
+
include_context 'globals'
|
7
|
+
|
8
|
+
describe "accessors" do
|
9
|
+
after{ clear_blockchain! }
|
10
|
+
|
11
|
+
it "compiles a simple profile" do
|
12
|
+
Dropzone::Buyer.sham!(:build).save! test_privkey
|
13
|
+
|
14
|
+
profile = Dropzone::BuyerProfile.new test_pubkey
|
15
|
+
|
16
|
+
expect(profile.valid?).to be_truthy
|
17
|
+
expect(profile.description).to eq("abc")
|
18
|
+
expect(profile.alias).to eq("Satoshi")
|
19
|
+
expect(profile.addr).to eq(test_pubkey)
|
20
|
+
expect(profile.active?).to be_truthy
|
21
|
+
end
|
22
|
+
|
23
|
+
it "combines attributes from mulitple messages" do
|
24
|
+
Dropzone::Buyer.sham!(:build).save! test_privkey
|
25
|
+
Dropzone::Buyer.sham!(:build, :description => 'xyz').save! test_privkey
|
26
|
+
|
27
|
+
profile = Dropzone::BuyerProfile.new test_pubkey
|
28
|
+
|
29
|
+
expect(profile.valid?).to be_truthy
|
30
|
+
expect(profile.description).to eq("xyz")
|
31
|
+
expect(profile.alias).to eq("Satoshi")
|
32
|
+
expect(profile.addr).to eq(test_pubkey)
|
33
|
+
expect(profile.active?).to be_truthy
|
34
|
+
end
|
35
|
+
|
36
|
+
it "supports profile transfers" do
|
37
|
+
# Standard Buyer:
|
38
|
+
Dropzone::Buyer.sham!(:build).save! test_privkey
|
39
|
+
|
40
|
+
# Buyer Transfer to Tester2:
|
41
|
+
Dropzone::Buyer.new( receiver_addr: TESTER2_PUBLIC_KEY,
|
42
|
+
transfer_pkey: TESTER2_PUBLIC_KEY).save! test_privkey
|
43
|
+
|
44
|
+
# And let's update Tester2 for some added complexity:
|
45
|
+
Dropzone::Buyer.new( receiver_addr: TESTER2_PUBLIC_KEY,
|
46
|
+
:alias => 'New Alias' ).save! TESTER2_PRIVATE_KEY
|
47
|
+
|
48
|
+
profile = Dropzone::BuyerProfile.new TESTER2_PUBLIC_KEY
|
49
|
+
|
50
|
+
expect(profile.valid?).to be_truthy
|
51
|
+
expect(profile.description).to eq("abc")
|
52
|
+
expect(profile.alias).to eq("New Alias")
|
53
|
+
expect(profile.addr).to eq(TESTER2_PUBLIC_KEY)
|
54
|
+
expect(profile.active?).to be_truthy
|
55
|
+
end
|
56
|
+
|
57
|
+
it "supports a transfer in and transfer out" do
|
58
|
+
# Standard Buyer:
|
59
|
+
Dropzone::Buyer.sham!(:build).save! test_privkey
|
60
|
+
|
61
|
+
# Address 1 transfers to Address 2:
|
62
|
+
Dropzone::Buyer.new( receiver_addr: TESTER2_PUBLIC_KEY,
|
63
|
+
transfer_pkey: TESTER2_PUBLIC_KEY).save! test_privkey
|
64
|
+
|
65
|
+
# Address 2 transfers to Address 3:
|
66
|
+
Dropzone::Buyer.new( receiver_addr: TESTER3_PUBLIC_KEY,
|
67
|
+
transfer_pkey: TESTER3_PUBLIC_KEY).save! TESTER2_PRIVATE_KEY
|
68
|
+
|
69
|
+
profile = Dropzone::BuyerProfile.new TESTER3_PUBLIC_KEY
|
70
|
+
|
71
|
+
expect(profile.valid?).to be_truthy
|
72
|
+
expect(profile.description).to eq("abc")
|
73
|
+
expect(profile.alias).to eq("Satoshi")
|
74
|
+
expect(profile.addr).to eq(TESTER3_PUBLIC_KEY)
|
75
|
+
expect(profile.active?).to be_truthy
|
76
|
+
end
|
77
|
+
|
78
|
+
it "only supports a single transfer in" do
|
79
|
+
# Address 1 Declaration:
|
80
|
+
Dropzone::Buyer.sham!(:build).save! test_privkey
|
81
|
+
|
82
|
+
# Address 2 Declaration:
|
83
|
+
Dropzone::Buyer.new( description: 'xyz', alias: 'New Alias',
|
84
|
+
receiver_addr: TESTER2_PUBLIC_KEY ).save! TESTER2_PRIVATE_KEY
|
85
|
+
|
86
|
+
# Address 1 transfers to Address 3:
|
87
|
+
Dropzone::Buyer.new( receiver_addr: TESTER3_PUBLIC_KEY,
|
88
|
+
transfer_pkey: TESTER3_PUBLIC_KEY).save! test_privkey
|
89
|
+
|
90
|
+
# Address 2 transfers to Address 3:
|
91
|
+
Dropzone::Buyer.new( receiver_addr: TESTER3_PUBLIC_KEY,
|
92
|
+
transfer_pkey: TESTER3_PUBLIC_KEY).save! TESTER2_PRIVATE_KEY
|
93
|
+
|
94
|
+
profile = Dropzone::BuyerProfile.new TESTER3_PUBLIC_KEY
|
95
|
+
|
96
|
+
expect(profile.valid?).to be_truthy
|
97
|
+
expect(profile.description).to eq("abc")
|
98
|
+
expect(profile.alias).to eq("Satoshi")
|
99
|
+
expect(profile.addr).to eq(TESTER3_PUBLIC_KEY)
|
100
|
+
expect(profile.transfer_pkey).to be_nil
|
101
|
+
expect(profile.active?).to be_truthy
|
102
|
+
end
|
103
|
+
|
104
|
+
it "supports deactivation" do
|
105
|
+
# Standard Buyer:
|
106
|
+
Dropzone::Buyer.sham!(:build).save! test_privkey
|
107
|
+
|
108
|
+
# Buyer Deactivates his account:
|
109
|
+
Dropzone::Buyer.new( receiver_addr: test_pubkey,
|
110
|
+
transfer_pkey: 0).save! test_privkey
|
111
|
+
|
112
|
+
profile = Dropzone::BuyerProfile.new test_pubkey
|
113
|
+
|
114
|
+
expect(profile.transfer_pkey).to eq(0)
|
115
|
+
expect(profile.active?).to be_falsey
|
116
|
+
expect(profile.closed?).to be_truthy
|
117
|
+
end
|
118
|
+
|
119
|
+
it "will stop merging attributes after a transfer out" do
|
120
|
+
# Standard Buyer:
|
121
|
+
Dropzone::Buyer.sham!(:build).save! test_privkey
|
122
|
+
|
123
|
+
# Address 1 transfers to Address 2:
|
124
|
+
Dropzone::Buyer.new( receiver_addr: TESTER2_PUBLIC_KEY,
|
125
|
+
transfer_pkey: TESTER2_PUBLIC_KEY).save! test_privkey
|
126
|
+
|
127
|
+
# Address 1 changes description:
|
128
|
+
Dropzone::Buyer.new( description: 'xyz' ).save! test_privkey
|
129
|
+
|
130
|
+
profile1 = Dropzone::BuyerProfile.new test_pubkey
|
131
|
+
profile2 = Dropzone::BuyerProfile.new TESTER2_PUBLIC_KEY
|
132
|
+
|
133
|
+
expect(profile1.description).to eq("abc")
|
134
|
+
expect(profile1.alias).to eq("Satoshi")
|
135
|
+
expect(profile1.addr).to eq(test_pubkey)
|
136
|
+
expect(profile1.transfer_pkey).to eq(TESTER2_PUBLIC_KEY)
|
137
|
+
expect(profile1.active?).to be_falsey
|
138
|
+
expect(profile1.closed?).to be_falsey
|
139
|
+
|
140
|
+
expect(profile2.description).to eq("abc")
|
141
|
+
expect(profile2.alias).to eq("Satoshi")
|
142
|
+
expect(profile2.addr).to eq(TESTER2_PUBLIC_KEY)
|
143
|
+
expect(profile2.active?).to be_truthy
|
144
|
+
expect(profile2.closed?).to be_falsey
|
145
|
+
end
|
146
|
+
|
147
|
+
it "will stop merging attributes after a cancellation" do
|
148
|
+
# Standard Buyer:
|
149
|
+
Dropzone::Buyer.sham!(:build).save! test_privkey
|
150
|
+
|
151
|
+
# Address 1 closes its account:
|
152
|
+
Dropzone::Buyer.new( receiver_addr: test_pubkey,
|
153
|
+
transfer_pkey: 0 ).save! test_privkey
|
154
|
+
|
155
|
+
# Address 1 changes description:
|
156
|
+
Dropzone::Buyer.new( description: 'xyz' ).save! test_privkey
|
157
|
+
|
158
|
+
profile = Dropzone::BuyerProfile.new test_pubkey
|
159
|
+
|
160
|
+
expect(profile.valid?).to be_truthy
|
161
|
+
expect(profile.description).to eq("abc")
|
162
|
+
expect(profile.alias).to eq("Satoshi")
|
163
|
+
expect(profile.addr).to eq(test_pubkey)
|
164
|
+
expect(profile.transfer_pkey).to eq(0)
|
165
|
+
expect(profile.active?).to be_falsey
|
166
|
+
end
|
167
|
+
|
168
|
+
it "will merge attributes in a cancellation message" do
|
169
|
+
# Standard Buyer:
|
170
|
+
Dropzone::Buyer.sham!(:build).save! test_privkey
|
171
|
+
|
172
|
+
# Address 1 closes its account:
|
173
|
+
Dropzone::Buyer.new( receiver_addr: test_pubkey, description: 'xyz',
|
174
|
+
transfer_pkey: 0 ).save! test_privkey
|
175
|
+
|
176
|
+
profile = Dropzone::BuyerProfile.new test_pubkey
|
177
|
+
|
178
|
+
expect(profile.valid?).to be_truthy
|
179
|
+
expect(profile.description).to eq("xyz")
|
180
|
+
expect(profile.alias).to eq("Satoshi")
|
181
|
+
expect(profile.addr).to eq(test_pubkey)
|
182
|
+
expect(profile.transfer_pkey).to eq(0)
|
183
|
+
expect(profile.active?).to be_falsey
|
184
|
+
end
|
185
|
+
|
186
|
+
it "will merge attributes in a transfer message" do
|
187
|
+
# Standard Buyer:
|
188
|
+
Dropzone::Buyer.sham!(:build).save! test_privkey
|
189
|
+
|
190
|
+
# Address 1 closes its account:
|
191
|
+
Dropzone::Buyer.new( receiver_addr: TESTER2_PUBLIC_KEY, description: 'xyz',
|
192
|
+
transfer_pkey: TESTER2_PUBLIC_KEY ).save! test_privkey
|
193
|
+
|
194
|
+
profile = Dropzone::BuyerProfile.new test_pubkey
|
195
|
+
|
196
|
+
expect(profile.valid?).to be_truthy
|
197
|
+
expect(profile.description).to eq("xyz")
|
198
|
+
expect(profile.alias).to eq("Satoshi")
|
199
|
+
expect(profile.addr).to eq(test_pubkey)
|
200
|
+
expect(profile.transfer_pkey).to eq(TESTER2_PUBLIC_KEY)
|
201
|
+
expect(profile.active?).to be_falsey
|
202
|
+
end
|
203
|
+
|
204
|
+
it "won't compile a deactivated transfer" do
|
205
|
+
# Standard Buyer:
|
206
|
+
Dropzone::Buyer.sham!(:build).save! test_privkey
|
207
|
+
|
208
|
+
# Address 1 closes its account:
|
209
|
+
Dropzone::Buyer.new( receiver_addr: test_pubkey,
|
210
|
+
transfer_pkey: 0 ).save! test_privkey
|
211
|
+
|
212
|
+
# Address 1 transfers its account:
|
213
|
+
Dropzone::Buyer.new( receiver_addr: TESTER2_PUBLIC_KEY,
|
214
|
+
transfer_pkey: TESTER2_PUBLIC_KEY ).save! test_privkey
|
215
|
+
|
216
|
+
profile = Dropzone::BuyerProfile.new TESTER2_PUBLIC_KEY
|
217
|
+
|
218
|
+
expect(profile.valid?).to be_falsey
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
describe "validations" do
|
223
|
+
after{ clear_blockchain! }
|
224
|
+
|
225
|
+
it "requires a valid buyer message" do
|
226
|
+
# No messages have been created here yet:
|
227
|
+
profile = Dropzone::BuyerProfile.new test_pubkey
|
228
|
+
|
229
|
+
expect(profile.valid?).to be_falsey
|
230
|
+
expect(profile.errors.count).to eq(1)
|
231
|
+
expect(profile.errors.on(:addr)).to eq(['profile not found'])
|
232
|
+
end
|
233
|
+
|
234
|
+
it "won't accept a closed account transfer" do
|
235
|
+
# Standard Buyer:
|
236
|
+
Dropzone::Buyer.sham!(:build).save! test_privkey
|
237
|
+
|
238
|
+
# Address 1 closes its account:
|
239
|
+
Dropzone::Buyer.new( receiver_addr: test_pubkey,
|
240
|
+
transfer_pkey: 0 ).save! test_privkey
|
241
|
+
|
242
|
+
# Address 1 transfers its account:
|
243
|
+
Dropzone::Buyer.new( receiver_addr: TESTER2_PUBLIC_KEY,
|
244
|
+
transfer_pkey: TESTER2_PUBLIC_KEY ).save! test_privkey
|
245
|
+
|
246
|
+
profile = Dropzone::BuyerProfile.new TESTER2_PUBLIC_KEY
|
247
|
+
expect(profile.valid?).to be_falsey
|
248
|
+
expect(profile.errors.count).to eq(1)
|
249
|
+
expect(profile.errors.on(:prior_profile)).to eq(['invalid transfer or closed'])
|
250
|
+
end
|
251
|
+
|
252
|
+
it "won't accept a second transfer out" do
|
253
|
+
# Standard Buyer:
|
254
|
+
Dropzone::Buyer.sham!(:build).save! test_privkey
|
255
|
+
|
256
|
+
# Address 1 transfers to address 2:
|
257
|
+
Dropzone::Buyer.new( receiver_addr: TESTER2_PUBLIC_KEY,
|
258
|
+
transfer_pkey: TESTER2_PUBLIC_KEY ).save! test_privkey
|
259
|
+
|
260
|
+
# Address 1 transfers to address 3:
|
261
|
+
Dropzone::Buyer.new( receiver_addr: TESTER3_PUBLIC_KEY,
|
262
|
+
transfer_pkey: TESTER3_PUBLIC_KEY ).save! test_privkey
|
263
|
+
|
264
|
+
profile2 = Dropzone::BuyerProfile.new TESTER2_PUBLIC_KEY
|
265
|
+
profile3 = Dropzone::BuyerProfile.new TESTER3_PUBLIC_KEY
|
266
|
+
|
267
|
+
expect(profile2.valid?).to be_truthy
|
268
|
+
expect(profile2.description).to eq("abc")
|
269
|
+
expect(profile2.alias).to eq("Satoshi")
|
270
|
+
expect(profile2.addr).to eq(TESTER2_PUBLIC_KEY)
|
271
|
+
expect(profile2.active?).to be_truthy
|
272
|
+
|
273
|
+
expect(profile3.valid?).to be_falsey
|
274
|
+
expect(profile3.errors.count).to eq(1)
|
275
|
+
expect(profile3.errors.on(:prior_profile)).to eq(['invalid transfer or closed'])
|
276
|
+
end
|
277
|
+
|
278
|
+
end
|
279
|
+
end
|