zold 0.0.7 → 0.0.8
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.
- checksums.yaml +4 -4
- data/README.md +24 -28
- data/lib/zold/key.rb +15 -2
- data/lib/zold/version.rb +1 -1
- data/lib/zold/wallet.rb +42 -85
- data/lib/zold/wallets.rb +1 -1
- data/test/commands/test_create.rb +2 -2
- data/test/test_key.rb +17 -10
- data/test/test_wallet.rb +21 -6
- data/zold.gemspec +0 -1
- metadata +2 -17
- data/assets/wallet.xsd +0 -71
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5306e5717fd5e9e5e42148d1e46446895b24b48d
|
4
|
+
data.tar.gz: a47d42f9786ed85e65a35026ccca2f0f292bd9e3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2c93b3dd2db0fb07b521c0920112f743dff5574219ac6c19f9ebc5ec73126b3f671bb9ca71a53a9128c43455e558c6e4293e3c507efeb468202765783935e1e6
|
7
|
+
data.tar.gz: 89a74ea62a573ba9f3eff0481083780a41fe212e5c2cea9b325a3d343168df4b264f8152600290fdcca70e76129653b19c80a7dffaf1255efcc8809e32e8fbed
|
data/README.md
CHANGED
@@ -36,7 +36,7 @@ ZOLD principles include:
|
|
36
36
|
* There is no mining; the only way to get ZOLD is to receive it from someone else
|
37
37
|
* Only 2<sup>63</sup> numerals (no fractions) can technically be issued
|
38
38
|
* The first wallet belongs to the issuer and may have a negative balance
|
39
|
-
* A wallet is an
|
39
|
+
* A wallet is an plain text file
|
40
40
|
* There is no central ledger, each wallet has its own personal ledger
|
41
41
|
* Each transaction in the ledger is confirmed by [RSA](https://simple.wikipedia.org/wiki/RSA_%28algorithm%29) encryption
|
42
42
|
* The network of communicating nodes maintains wallets of users
|
@@ -84,40 +84,36 @@ A **transaction** is a money transferring operation between two wallets.
|
|
84
84
|
|
85
85
|
A wallet may look like this:
|
86
86
|
|
87
|
-
```
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
[...]
|
93
|
-
<txn id="35">
|
94
|
-
<date>2017-07-19T21:24:51.136Z</date>
|
95
|
-
<beneficiary>927284</beneficiary>
|
96
|
-
<amount>-560</amount>
|
97
|
-
<sign><!-- RSA signature of the payer --></sign>
|
98
|
-
</txn>
|
99
|
-
</ledger>
|
100
|
-
</wallet>
|
87
|
+
```text
|
88
|
+
12345678abcdef
|
89
|
+
AAAAB3NzaC1yc2EAAAADAQABAAABAQCuLuVr4Tl2sXoN5Zb7b6SKMPrVjLxb...
|
90
|
+
|
91
|
+
35;2017-07-19T21:24:51.136Z;98bb82c81735c4ee;-560;SKMPrVjLxbM5oDm0IhniQQy3shF...
|
101
92
|
```
|
102
93
|
|
103
|
-
|
94
|
+
Lines are separated by either CR or CRLF, doesn't matter.
|
95
|
+
|
96
|
+
The fist line is wallet ID, a 64-bit unsigned integer.
|
97
|
+
|
98
|
+
The second line is a public RSA key of the wallet owner.
|
99
|
+
|
100
|
+
The third line is empty.
|
101
|
+
|
102
|
+
Each next line is a transaction and it has four or five fields separated by a semi-colon.
|
103
|
+
|
104
|
+
The first field is transaction ID, an unsigned 16-bit integer.
|
104
105
|
|
105
|
-
|
106
|
+
The second field is its date, in ISO 8601 format.
|
106
107
|
|
107
|
-
|
108
|
-
milliseconds since
|
109
|
-
[epoch](https://en.wikipedia.org/wiki/Epoch_%28reference_date%29).
|
108
|
+
The third field is the wallet ID of the beneficiary.
|
110
109
|
|
111
|
-
|
112
|
-
2<sup>24</sup> (16,777,216). Thus, the technical capacity
|
113
|
-
of the currency is 549,755,813,888 (half a trillion).
|
110
|
+
The forth field is the amount.
|
114
111
|
|
115
|
-
The
|
116
|
-
It contains an RSA signature of a data block, created by the wallet owner:
|
117
|
-
`date`, `amount`, `beneficiary` and
|
118
|
-
64 bytes of [salt](https://en.wikipedia.org/wiki/Salt_%28cryptography%29).
|
112
|
+
The fifth field is an RSA signature of "ID;beneficiary;amount" text.
|
119
113
|
|
120
|
-
|
114
|
+
1ZLD by convention equals to 2<sup>24</sup> (16,777,216).
|
115
|
+
Thus, the technical capacity of the currency is
|
116
|
+
549,755,813,888 (half a trillion).
|
121
117
|
|
122
118
|
## Architecture
|
123
119
|
|
data/lib/zold/key.rb
CHANGED
@@ -34,13 +34,22 @@ module Zold
|
|
34
34
|
raise "Can't find RSA key at #{file} (#{path})" unless File.exist?(path)
|
35
35
|
@body = File.read(path)
|
36
36
|
end
|
37
|
-
|
37
|
+
return if text.nil?
|
38
|
+
@body = [
|
39
|
+
'-----BEGIN PUBLIC KEY-----',
|
40
|
+
text.gsub(/(?<=\G.{64})/, "\n"),
|
41
|
+
'-----END PUBLIC KEY-----'
|
42
|
+
].join("\n")
|
38
43
|
end
|
39
44
|
|
40
45
|
def to_s
|
41
46
|
rsa.to_s.strip
|
42
47
|
end
|
43
48
|
|
49
|
+
def to_pub
|
50
|
+
to_s.delete("\n").gsub(/-{5}[ A-Z]+-{5}/, '')
|
51
|
+
end
|
52
|
+
|
44
53
|
def sign(text)
|
45
54
|
Base64.encode64(rsa.sign(OpenSSL::Digest::SHA256.new, text)).delete("\n")
|
46
55
|
end
|
@@ -56,7 +65,11 @@ module Zold
|
|
56
65
|
unless text.start_with?('-----BEGIN')
|
57
66
|
text = OpenSSHKeyConverter.decode_pubkey(text.split[1])
|
58
67
|
end
|
59
|
-
|
68
|
+
begin
|
69
|
+
OpenSSL::PKey::RSA.new(text)
|
70
|
+
rescue OpenSSL::PKey::RSAError => e
|
71
|
+
raise "Can't read RSA key (#{e.message}): #{text}"
|
72
|
+
end
|
60
73
|
end
|
61
74
|
end
|
62
75
|
end
|
data/lib/zold/version.rb
CHANGED
data/lib/zold/wallet.rb
CHANGED
@@ -18,7 +18,6 @@
|
|
18
18
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
19
|
# SOFTWARE.
|
20
20
|
|
21
|
-
require 'nokogiri'
|
22
21
|
require 'time'
|
23
22
|
|
24
23
|
# The wallet.
|
@@ -33,7 +32,7 @@ module Zold
|
|
33
32
|
end
|
34
33
|
|
35
34
|
def to_s
|
36
|
-
id
|
35
|
+
id.to_s
|
37
36
|
end
|
38
37
|
|
39
38
|
def exists?
|
@@ -46,30 +45,12 @@ module Zold
|
|
46
45
|
|
47
46
|
def init(id, pubkey)
|
48
47
|
raise "File '#{@file}' already exists" if File.exist?(@file)
|
49
|
-
File.write(
|
50
|
-
@file,
|
51
|
-
valid(
|
52
|
-
Nokogiri::XML::Builder.new do |xml|
|
53
|
-
xml.wallet do
|
54
|
-
xml.id_ id.to_s
|
55
|
-
xml.pkey pubkey.to_s
|
56
|
-
xml.ledger {}
|
57
|
-
end
|
58
|
-
end.doc
|
59
|
-
)
|
60
|
-
)
|
48
|
+
File.write(@file, "#{id}\n#{pubkey.to_pub}\n\n")
|
61
49
|
end
|
62
50
|
|
63
51
|
def version
|
64
|
-
|
65
|
-
|
66
|
-
unless xml.xpath('/wallet/ledger[txn]').empty?
|
67
|
-
ver = xml.xpath('/wallet/ledger/txn/@id')
|
68
|
-
.map(&:to_s)
|
69
|
-
.map(&:to_i)
|
70
|
-
.max
|
71
|
-
end
|
72
|
-
ver
|
52
|
+
all = txns
|
53
|
+
all.empty? ? 0 : all.map { |t| t[0] }.map(&:to_i).max
|
73
54
|
end
|
74
55
|
|
75
56
|
def root?
|
@@ -77,67 +58,63 @@ module Zold
|
|
77
58
|
end
|
78
59
|
|
79
60
|
def id
|
80
|
-
Id.new(
|
61
|
+
Id.new(lines[0])
|
81
62
|
end
|
82
63
|
|
83
64
|
def balance
|
84
65
|
Amount.new(
|
85
|
-
coins:
|
86
|
-
.map(&:to_s)
|
87
|
-
.map(&:to_i)
|
88
|
-
.inject(0) { |sum, n| sum + n }
|
66
|
+
coins: txns.map { |t| t[2] }.map(&:to_i).inject(0) { |sum, n| sum + n }
|
89
67
|
)
|
90
68
|
end
|
91
69
|
|
92
70
|
def sub(amount, target, pvtkey)
|
93
|
-
xml = load
|
94
71
|
date = Time.now
|
95
72
|
txn = version + 1
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
)
|
104
|
-
|
105
|
-
|
73
|
+
line = [
|
74
|
+
txn,
|
75
|
+
date.iso8601,
|
76
|
+
-amount.to_i,
|
77
|
+
target,
|
78
|
+
pvtkey.sign("#{txn};#{amount.to_i};#{target}")
|
79
|
+
].join(';') + "\n"
|
80
|
+
File.write(@file, (lines << line).join(''))
|
81
|
+
{
|
82
|
+
id: txn,
|
83
|
+
date: date,
|
84
|
+
amount: amount,
|
85
|
+
beneficiary: id
|
86
|
+
}
|
106
87
|
end
|
107
88
|
|
108
89
|
def add(txn)
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
90
|
+
line = [
|
91
|
+
"/#{txn[:id]}",
|
92
|
+
txn[:date].iso8601,
|
93
|
+
txn[:amount].to_i,
|
94
|
+
txn[:beneficiary]
|
95
|
+
].join(';') + "\n"
|
96
|
+
File.write(@file, (lines << line).join(''))
|
116
97
|
end
|
117
98
|
|
118
99
|
def check(id, amount, beneficiary)
|
119
|
-
|
120
|
-
|
121
|
-
xamount = Amount.new(
|
122
|
-
coins: txn.xpath('amount/text()')[0].to_s.to_i
|
123
|
-
).mul(-1)
|
100
|
+
txn = txns.find { |t| t[0].to_i == id }
|
101
|
+
raise "Transaction ##{id} not found" if txn.nil?
|
102
|
+
xamount = Amount.new(coins: txn[2].to_i).mul(-1)
|
124
103
|
raise "#{xamount} != #{amount}" if xamount != amount
|
125
|
-
xbeneficiary = Id.new(txn
|
104
|
+
xbeneficiary = Id.new(txn[3].to_s)
|
126
105
|
raise "#{xbeneficiary} != #{beneficiary}" if xbeneficiary != beneficiary
|
127
|
-
data = "#{id}
|
128
|
-
valid = Key.new(text:
|
129
|
-
txn.xpath('sign/text()')[0].to_s, data
|
130
|
-
)
|
106
|
+
data = "#{id};#{amount.to_i};#{beneficiary}"
|
107
|
+
valid = Key.new(text: lines[1].strip).verify(txn[4], data)
|
131
108
|
raise "Signature is not confirming this data: '#{data}'" unless valid
|
132
109
|
true
|
133
110
|
end
|
134
111
|
|
135
112
|
def income
|
136
|
-
|
113
|
+
txns.select { |t| t[2].to_i > 0 }.each do |t|
|
137
114
|
hash = {
|
138
|
-
id:
|
139
|
-
beneficiary: Id.new(
|
140
|
-
amount: Amount.new(coins:
|
115
|
+
id: t[0][1..-1].to_i,
|
116
|
+
beneficiary: Id.new(t[3]),
|
117
|
+
amount: Amount.new(coins: t[2].to_i)
|
141
118
|
}
|
142
119
|
yield hash
|
143
120
|
end
|
@@ -145,33 +122,13 @@ module Zold
|
|
145
122
|
|
146
123
|
private
|
147
124
|
|
148
|
-
def
|
149
|
-
|
150
|
-
valid(Nokogiri::XML(File.read(@file)))
|
151
|
-
end
|
152
|
-
|
153
|
-
def save(xml)
|
154
|
-
File.write(@file, valid(xml).to_s)
|
125
|
+
def txns
|
126
|
+
lines.drop(3).map { |t| t.split(';') }
|
155
127
|
end
|
156
128
|
|
157
|
-
def
|
158
|
-
|
159
|
-
|
160
|
-
File.join(
|
161
|
-
File.dirname(__FILE__),
|
162
|
-
'../../assets/wallet.xsd'
|
163
|
-
)
|
164
|
-
)
|
165
|
-
)
|
166
|
-
errors = xsd.validate(xml)
|
167
|
-
unless errors.empty?
|
168
|
-
errors.each do |error|
|
169
|
-
puts "#{p} #{error.line}: #{error.message}"
|
170
|
-
end
|
171
|
-
puts xml
|
172
|
-
raise 'XML is not valid'
|
173
|
-
end
|
174
|
-
xml
|
129
|
+
def lines
|
130
|
+
raise "File '#{@file}' is absent" unless File.exist?(@file)
|
131
|
+
File.readlines(@file)
|
175
132
|
end
|
176
133
|
end
|
177
134
|
end
|
data/lib/zold/wallets.rb
CHANGED
@@ -37,8 +37,8 @@ class TestCreate < Minitest::Test
|
|
37
37
|
).run
|
38
38
|
assert wallet.balance.zero?
|
39
39
|
assert(
|
40
|
-
File.exist?(File.join(dir,
|
41
|
-
"Wallet file not found: #{wallet.id}
|
40
|
+
File.exist?(File.join(dir, wallet.id.to_s)),
|
41
|
+
"Wallet file not found: #{wallet.id}"
|
42
42
|
)
|
43
43
|
end
|
44
44
|
end
|
data/test/test_key.rb
CHANGED
@@ -29,14 +29,16 @@ require_relative '../lib/zold/key.rb'
|
|
29
29
|
class TestKey < Minitest::Test
|
30
30
|
def test_reads_public_rsa
|
31
31
|
key = Zold::Key.new(file: 'fixtures/id_rsa.pub')
|
32
|
-
assert key.
|
33
|
-
assert key.
|
32
|
+
assert key.to_pub.start_with?('MIICI')
|
33
|
+
assert key.to_pub.end_with?('EAAQ==')
|
34
|
+
assert !key.to_pub.include?("\n")
|
35
|
+
assert Zold::Key.new(text: key.to_pub).to_pub.start_with?('MIICI')
|
34
36
|
end
|
35
37
|
|
36
38
|
def test_reads_private_rsa
|
37
39
|
key = Zold::Key.new(file: 'fixtures/id_rsa')
|
38
|
-
assert key.
|
39
|
-
assert key.
|
40
|
+
assert key.to_pub.start_with?('MIIJJ')
|
41
|
+
assert key.to_pub.end_with?('Sg==')
|
40
42
|
end
|
41
43
|
|
42
44
|
def test_signs_and_verifies
|
@@ -48,11 +50,16 @@ class TestKey < Minitest::Test
|
|
48
50
|
end
|
49
51
|
|
50
52
|
def test_signs_and_verifies_with_random_key
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
53
|
+
Dir.mktmpdir 'test' do |dir|
|
54
|
+
key = OpenSSL::PKey::RSA.new(2048)
|
55
|
+
file = File.join(dir, 'temp')
|
56
|
+
File.write(file, key.public_key.to_s)
|
57
|
+
pub = Zold::Key.new(file: file)
|
58
|
+
File.write(file, key.to_s)
|
59
|
+
pvt = Zold::Key.new(file: file)
|
60
|
+
text = 'How are you doing, dude?'
|
61
|
+
signature = pvt.sign(text)
|
62
|
+
assert pub.verify(signature, text)
|
63
|
+
end
|
57
64
|
end
|
58
65
|
end
|
data/test/test_wallet.rb
CHANGED
@@ -36,13 +36,28 @@ class TestWallet < Minitest::Test
|
|
36
36
|
wallet = wallet(dir)
|
37
37
|
amount = Zold::Amount.new(zld: 39.99)
|
38
38
|
key = Zold::Key.new(file: 'fixtures/id_rsa')
|
39
|
-
assert
|
39
|
+
assert(
|
40
|
+
wallet.version.zero?,
|
41
|
+
"Wallet version #{wallet.version} is not equal to zero"
|
42
|
+
)
|
40
43
|
wallet.sub(amount, Zold::Id.new, key)
|
44
|
+
assert(
|
45
|
+
wallet.version == 1,
|
46
|
+
"Wallet version #{wallet.version} is not equal to 1"
|
47
|
+
)
|
41
48
|
wallet.sub(amount, Zold::Id.new, key)
|
42
|
-
assert wallet.version == 2
|
43
49
|
assert(
|
44
|
-
wallet.
|
45
|
-
"#{wallet.
|
50
|
+
wallet.version == 2,
|
51
|
+
"Wallet version #{wallet.version} is not equal to 2"
|
52
|
+
)
|
53
|
+
wallet.sub(amount, Zold::Id.new, key)
|
54
|
+
assert(
|
55
|
+
wallet.version == 3,
|
56
|
+
"Wallet version #{wallet.version} is not equal to 3"
|
57
|
+
)
|
58
|
+
assert(
|
59
|
+
wallet.balance == amount.mul(-3),
|
60
|
+
"#{wallet.balance} is not equal to #{amount.mul(-3)}"
|
46
61
|
)
|
47
62
|
end
|
48
63
|
end
|
@@ -51,7 +66,7 @@ class TestWallet < Minitest::Test
|
|
51
66
|
Dir.mktmpdir 'test' do |dir|
|
52
67
|
pkey = Zold::Key.new(file: 'fixtures/id_rsa.pub')
|
53
68
|
Dir.chdir(dir) do
|
54
|
-
file = File.join(dir, 'source
|
69
|
+
file = File.join(dir, 'source')
|
55
70
|
wallet = Zold::Wallet.new(file)
|
56
71
|
id = Zold::Id.new.to_s
|
57
72
|
wallet.init(id, pkey)
|
@@ -105,7 +120,7 @@ class TestWallet < Minitest::Test
|
|
105
120
|
|
106
121
|
def wallet(dir)
|
107
122
|
id = Zold::Id.new
|
108
|
-
file = File.join(dir,
|
123
|
+
file = File.join(dir, id.to_s)
|
109
124
|
wallet = Zold::Wallet.new(file)
|
110
125
|
wallet.init(id, Zold::Key.new(file: 'fixtures/id_rsa.pub'))
|
111
126
|
wallet
|
data/zold.gemspec
CHANGED
@@ -46,7 +46,6 @@ Gem::Specification.new do |s|
|
|
46
46
|
s.extra_rdoc_files = ['README.md', 'LICENSE.txt']
|
47
47
|
s.add_runtime_dependency 'cucumber', '1.3.17'
|
48
48
|
s.add_runtime_dependency 'haml', '5.0.3'
|
49
|
-
s.add_runtime_dependency 'nokogiri', '~>1.8'
|
50
49
|
s.add_runtime_dependency 'rainbow', '~>3.0'
|
51
50
|
s.add_runtime_dependency 'rake', '12.0.0'
|
52
51
|
s.add_runtime_dependency 'rubocop', '~>0.52.0'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zold
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yegor Bugayenko
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-02-
|
11
|
+
date: 2018-02-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: cucumber
|
@@ -38,20 +38,6 @@ dependencies:
|
|
38
38
|
- - '='
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 5.0.3
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: nokogiri
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - "~>"
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '1.8'
|
48
|
-
type: :runtime
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - "~>"
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '1.8'
|
55
41
|
- !ruby/object:Gem::Dependency
|
56
42
|
name: rainbow
|
57
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -230,7 +216,6 @@ files:
|
|
230
216
|
- README.md
|
231
217
|
- Rakefile
|
232
218
|
- appveyor.yml
|
233
|
-
- assets/wallet.xsd
|
234
219
|
- bin/zold
|
235
220
|
- cucumber.yml
|
236
221
|
- deploy.sh
|
data/assets/wallet.xsd
DELETED
@@ -1,71 +0,0 @@
|
|
1
|
-
<?xml version="1.0"?>
|
2
|
-
<!--
|
3
|
-
(The MIT License)
|
4
|
-
|
5
|
-
Copyright (c) 2018 Zerocracy, Inc.
|
6
|
-
|
7
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8
|
-
of this software and associated documentation files (the 'Software'), to deal
|
9
|
-
in the Software without restriction, including without limitation the rights
|
10
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11
|
-
copies of the Software, and to permit persons to whom the Software is
|
12
|
-
furnished to do so, subject to the following conditions:
|
13
|
-
|
14
|
-
The above copyright notice and this permission notice shall be included in all
|
15
|
-
copies or substantial portions of the Software.
|
16
|
-
|
17
|
-
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
23
|
-
SOFTWARE.
|
24
|
-
-->
|
25
|
-
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
26
|
-
<xs:simpleType name="amount">
|
27
|
-
<xs:restriction base="xs:integer">
|
28
|
-
<xs:minInclusive value="-9223372036854775808"/>
|
29
|
-
<xs:maxInclusive value="9223372036854775807"/>
|
30
|
-
</xs:restriction>
|
31
|
-
</xs:simpleType>
|
32
|
-
<xs:simpleType name="wallet">
|
33
|
-
<xs:restriction base="xs:string">
|
34
|
-
<xs:pattern value="[0-9a-f]{16}"/>
|
35
|
-
</xs:restriction>
|
36
|
-
</xs:simpleType>
|
37
|
-
<xs:complexType name="txn">
|
38
|
-
<xs:all>
|
39
|
-
<xs:element name="beneficiary" type="wallet" minOccurs="1" maxOccurs="1"/>
|
40
|
-
<xs:element name="date" type="xs:dateTime" minOccurs="1" maxOccurs="1"/>
|
41
|
-
<xs:element name="sign" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
42
|
-
<xs:element name="amount" type="amount" minOccurs="1" maxOccurs="1"/>
|
43
|
-
</xs:all>
|
44
|
-
<xs:attribute name="id" use="required">
|
45
|
-
<xs:simpleType>
|
46
|
-
<xs:restriction base="xs:string">
|
47
|
-
<xs:pattern value="/?[0-9]+"/>
|
48
|
-
</xs:restriction>
|
49
|
-
</xs:simpleType>
|
50
|
-
</xs:attribute>
|
51
|
-
</xs:complexType>
|
52
|
-
<xs:complexType name="ledger">
|
53
|
-
<xs:sequence>
|
54
|
-
<xs:element name="txn" type="txn" minOccurs="0" maxOccurs="unbounded"/>
|
55
|
-
</xs:sequence>
|
56
|
-
</xs:complexType>
|
57
|
-
<xs:element name="wallet">
|
58
|
-
<xs:complexType>
|
59
|
-
<xs:all>
|
60
|
-
<xs:element name="id" type="wallet" minOccurs="1" maxOccurs="1"/>
|
61
|
-
<xs:element name="pkey" type="xs:string" minOccurs="1" maxOccurs="1"/>
|
62
|
-
<xs:element name="ledger" type="ledger" minOccurs="1" maxOccurs="1">
|
63
|
-
<xs:unique name="txnUnique">
|
64
|
-
<xs:selector xpath="./txn"/>
|
65
|
-
<xs:field xpath="@id"/>
|
66
|
-
</xs:unique>
|
67
|
-
</xs:element>
|
68
|
-
</xs:all>
|
69
|
-
</xs:complexType>
|
70
|
-
</xs:element>
|
71
|
-
</xs:schema>
|