xrbp 0.2.2 → 0.2.3
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/examples/nodestore1.rb +3 -1
- data/lib/xrbp/common.rb +6 -0
- data/lib/xrbp/core_ext.rb +21 -0
- data/lib/xrbp/nodestore/format.rb +76 -26
- data/lib/xrbp/nodestore/ledger.rb +46 -14
- data/lib/xrbp/nodestore/parser.rb +47 -14
- data/lib/xrbp/nodestore/protocol/indexes.rb +11 -8
- data/lib/xrbp/nodestore/protocol/issue.rb +15 -0
- data/lib/xrbp/nodestore/protocol/rate.rb +13 -1
- data/lib/xrbp/nodestore/shamap/node_factory.rb +6 -1
- data/lib/xrbp/nodestore/shamap/node_id.rb +2 -2
- data/lib/xrbp/nodestore/sle/st_amount.rb +46 -181
- data/lib/xrbp/nodestore/sle/st_amount_arithmatic.rb +126 -0
- data/lib/xrbp/nodestore/sle/st_amount_comparison.rb +49 -0
- data/lib/xrbp/nodestore/sle/st_amount_conversion.rb +203 -0
- data/lib/xrbp/nodestore/sqldb.rb +69 -4
- data/lib/xrbp/overlay/handshake.rb +1 -1
- data/lib/xrbp/version.rb +1 -1
- data/spec/xrbp/crypto/account_spec.rb +7 -2
- data/spec/xrbp/nodestore/amendments_spec.rb +11 -0
- data/spec/xrbp/nodestore/db_parser.rb +64 -1
- data/spec/xrbp/nodestore/fees_spec.rb +3 -0
- data/spec/xrbp/nodestore/ledger_access.rb +87 -2
- data/spec/xrbp/nodestore/protocol/indexes_spec.rb +43 -0
- data/spec/xrbp/nodestore/protocol/rate_spec.rb +12 -0
- data/spec/xrbp/nodestore/shamap/inner_node_spec.rb +44 -0
- data/spec/xrbp/nodestore/shamap/node_factory_spec.rb +9 -0
- data/spec/xrbp/nodestore/shamap/node_id_spec.rb +6 -0
- data/spec/xrbp/nodestore/shamap/node_spec.rb +25 -0
- data/spec/xrbp/nodestore/shamap_spec.rb +144 -0
- data/spec/xrbp/nodestore/sle/st_amount_arithmatic_spec.rb +7 -0
- data/spec/xrbp/nodestore/sle/st_amount_comparison_spec.rb +11 -0
- data/spec/xrbp/nodestore/sle/st_amount_conversion_spec.rb +64 -0
- data/spec/xrbp/nodestore/sle/st_amount_spec.rb +47 -0
- data/spec/xrbp/nodestore/sle/st_ledger_entry_spec.rb +5 -0
- data/spec/xrbp/nodestore/sle/st_object_spec.rb +29 -0
- metadata +20 -2
@@ -0,0 +1,49 @@
|
|
1
|
+
module XRBP
|
2
|
+
module NodeStore
|
3
|
+
class STAmount
|
4
|
+
module Comparison
|
5
|
+
def <(o)
|
6
|
+
return self < STAmount.new(:mantissa => o) if o.kind_of?(Numeric)
|
7
|
+
|
8
|
+
return neg if neg && !o.neg
|
9
|
+
if mantissa == 0
|
10
|
+
return false if o.neg
|
11
|
+
return o.mantissa != 0
|
12
|
+
end
|
13
|
+
|
14
|
+
return false if o.mantissa == 0
|
15
|
+
return neg if exponent > o.exponent
|
16
|
+
return !neg if exponent < o.exponent
|
17
|
+
return neg if mantissa > o.mantissa
|
18
|
+
return !neg if mantissa < o.mantissa
|
19
|
+
|
20
|
+
return false
|
21
|
+
end
|
22
|
+
|
23
|
+
def >=(o)
|
24
|
+
!(self < o)
|
25
|
+
end
|
26
|
+
|
27
|
+
def >(o)
|
28
|
+
self >= o && self != o
|
29
|
+
end
|
30
|
+
|
31
|
+
def ==(o)
|
32
|
+
return self == STAmount.new(:mantissa => o) if o.kind_of?(Numeric)
|
33
|
+
|
34
|
+
neg == o.neg &&
|
35
|
+
mantissa == o.mantissa &&
|
36
|
+
exponent == o.exponent
|
37
|
+
end
|
38
|
+
|
39
|
+
def <=>(o)
|
40
|
+
return self <=> STAmount.new(:mantissa => o) if o.kind_of?(Numeric)
|
41
|
+
|
42
|
+
return 0 if self == o
|
43
|
+
return -1 if self < o
|
44
|
+
return 1 if self > o
|
45
|
+
end
|
46
|
+
end # module Comparison
|
47
|
+
end # class STAmount
|
48
|
+
end # module NodeStore
|
49
|
+
end # module XRBP
|
@@ -0,0 +1,203 @@
|
|
1
|
+
module XRBP
|
2
|
+
module NodeStore
|
3
|
+
class STAmount
|
4
|
+
module Conversion
|
5
|
+
module ClassMethods
|
6
|
+
# @see {NodeStore::Parser::parse_amount}
|
7
|
+
def from_wire(data)
|
8
|
+
native = (data & STAmount::NOT_NATIVE) == 0
|
9
|
+
neg = (data & ~STAmount::NOT_NATIVE & STAmount::POS_NATIVE) == 0
|
10
|
+
value = (data & ~STAmount::NOT_NATIVE & ~STAmount::POS_NATIVE)
|
11
|
+
|
12
|
+
if native
|
13
|
+
STAmount.new :issue => NodeStore.xrp_issue,
|
14
|
+
:neg => neg,
|
15
|
+
:mantissa => value
|
16
|
+
else
|
17
|
+
exp = (value >> 54) - 97
|
18
|
+
mant = value & 0x3fffffffffffff
|
19
|
+
STAmount.new :neg => neg,
|
20
|
+
:exponent => exp,
|
21
|
+
:mantissa => mant
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Convert string to STAmount
|
26
|
+
#
|
27
|
+
# @see STAmount#amountFromString (in rippled)
|
28
|
+
def parse(str, issue=nil)
|
29
|
+
match = "^"+ # the beginning of the string
|
30
|
+
"([-+]?)"+ # (optional) + or - character
|
31
|
+
"(0|[1-9][0-9]*)"+ # a number (no leading zeroes, unless 0)
|
32
|
+
"(\\.([0-9]+))?"+ # (optional) period followed by any number
|
33
|
+
"([eE]([+-]?)([0-9]+))?"+ # (optional) E, optional + or -, any number
|
34
|
+
"$"
|
35
|
+
match = Regexp.new(match)
|
36
|
+
match = str.match(match)
|
37
|
+
raise "Number '#{str}' is not valid" unless match
|
38
|
+
|
39
|
+
# Match fields:
|
40
|
+
#
|
41
|
+
# 0 = whole input
|
42
|
+
# 1 = sign
|
43
|
+
# 2 = integer portion
|
44
|
+
# 3 = whole fraction (with '.')
|
45
|
+
# 4 = fraction (without '.')
|
46
|
+
# 5 = whole exponent (with 'e')
|
47
|
+
# 6 = exponent sign
|
48
|
+
# 7 = exponent number
|
49
|
+
|
50
|
+
raise "Number '#{str}' is overlong" if ((match[2] || "").length +
|
51
|
+
(match[4] || "").length) > 32
|
52
|
+
|
53
|
+
neg = !!match[1] && match[1] == '-'
|
54
|
+
|
55
|
+
raise "XRP must be specified in integral drops" if issue && issue.xrp? && !!match[3]
|
56
|
+
|
57
|
+
mantissa = 0
|
58
|
+
exponent = 0
|
59
|
+
|
60
|
+
if !match[4]
|
61
|
+
# integral only
|
62
|
+
mantissa = match[2].to_i
|
63
|
+
|
64
|
+
else
|
65
|
+
# integer and fraction
|
66
|
+
mantissa = (match[2] + match[4]).to_i
|
67
|
+
exponent = -(match[4].length)
|
68
|
+
end
|
69
|
+
|
70
|
+
if !!match[5]
|
71
|
+
# exponent
|
72
|
+
if match[6] && match[6] == '-'
|
73
|
+
exponent -= match[7].to_i
|
74
|
+
else
|
75
|
+
exponent += match[7].to_i
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
return STAmount.new :issue => issue,
|
80
|
+
:mantissa => mantissa,
|
81
|
+
:exponent => exponent,
|
82
|
+
:neg => neg
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.included(base)
|
87
|
+
base.extend(ClassMethods)
|
88
|
+
end
|
89
|
+
|
90
|
+
# Encode STAmount into binary format
|
91
|
+
def to_wire
|
92
|
+
xrp_bit = ((native? ? 0 : 1) << 63)
|
93
|
+
neg_bit = (( neg ? 0 : 1) << 62)
|
94
|
+
value_bits = native? ? mantissa :
|
95
|
+
(((exponent+97) << 54) + mantissa)
|
96
|
+
|
97
|
+
xrp_bit + neg_bit + value_bits
|
98
|
+
end
|
99
|
+
|
100
|
+
###
|
101
|
+
|
102
|
+
def to_h
|
103
|
+
{:mantissa => mantissa,
|
104
|
+
:exponent => exponent,
|
105
|
+
:neg => neg,
|
106
|
+
:issue => issue.to_h}
|
107
|
+
end
|
108
|
+
|
109
|
+
def negate!
|
110
|
+
return if zero?
|
111
|
+
@neg = !@neg
|
112
|
+
end
|
113
|
+
|
114
|
+
###
|
115
|
+
|
116
|
+
protected
|
117
|
+
|
118
|
+
def canonicalize
|
119
|
+
if native?
|
120
|
+
if @mantissa == 0
|
121
|
+
@exponent = 0
|
122
|
+
@neg = false
|
123
|
+
return
|
124
|
+
end
|
125
|
+
|
126
|
+
while @exponent < 0
|
127
|
+
@mantissa /= 10
|
128
|
+
@exponent += 1
|
129
|
+
end
|
130
|
+
|
131
|
+
while @exponent > 0
|
132
|
+
@mantissa *= 10
|
133
|
+
@exponent -= 1
|
134
|
+
end
|
135
|
+
|
136
|
+
raise if @mantissa > MAX_NATIVE
|
137
|
+
return
|
138
|
+
end
|
139
|
+
|
140
|
+
if @mantissa == 0
|
141
|
+
@exponent = -100
|
142
|
+
@negative = false
|
143
|
+
return
|
144
|
+
end
|
145
|
+
|
146
|
+
while ((@mantissa < MIN_VAL) && (@exponent > MIN_OFFSET))
|
147
|
+
@mantissa *= 10;
|
148
|
+
@exponent -= 1
|
149
|
+
end
|
150
|
+
|
151
|
+
while (@mantissa > MAX_VAL)
|
152
|
+
raise "value overflow" if (@exponent >= MAX_OFFSET)
|
153
|
+
|
154
|
+
@mantissa /= 10
|
155
|
+
@exponent += 1
|
156
|
+
end
|
157
|
+
|
158
|
+
if @exponent < MIN_OFFSET || @mantissa < MIN_VAL
|
159
|
+
@mantissa = 0;
|
160
|
+
@neg = false;
|
161
|
+
@exponent = -100;
|
162
|
+
return
|
163
|
+
end
|
164
|
+
|
165
|
+
raise "value overflow" if (@exponent > MAX_OFFSET)
|
166
|
+
|
167
|
+
raise unless @mantissa == 0 || (@mantissa >= MIN_VAL && @mantissa <= MAX_VAL)
|
168
|
+
raise unless @mantissa == 0 || (@exponent >= MIN_OFFSET && @exponent <= MAX_OFFSET)
|
169
|
+
raise unless @mantissa != 0 || @exponent != -100
|
170
|
+
end
|
171
|
+
|
172
|
+
public
|
173
|
+
|
174
|
+
def clear
|
175
|
+
# From rippled docs:
|
176
|
+
# The -100 is used to allow 0 to sort less than a small positive values
|
177
|
+
# which have a negative exponent.
|
178
|
+
@exponent = native? ? 0 : -100
|
179
|
+
|
180
|
+
@neg = false
|
181
|
+
@mantissa = 0
|
182
|
+
end
|
183
|
+
|
184
|
+
def sn_value
|
185
|
+
neg ? (-mantissa) : mantissa
|
186
|
+
end
|
187
|
+
|
188
|
+
###
|
189
|
+
|
190
|
+
# In drops!
|
191
|
+
def xrp_amount
|
192
|
+
neg ? (-value) : value
|
193
|
+
end
|
194
|
+
|
195
|
+
alias :drops :xrp_amount
|
196
|
+
|
197
|
+
def iou_amount
|
198
|
+
(neg ? -1 : 1) * mantissa * 10 ** exponent
|
199
|
+
end
|
200
|
+
end # module Conversion
|
201
|
+
end # class STAmount
|
202
|
+
end # module NodeStore
|
203
|
+
end # module XRBP
|
data/lib/xrbp/nodestore/sqldb.rb
CHANGED
@@ -2,22 +2,87 @@ require 'sqlite3'
|
|
2
2
|
|
3
3
|
module XRBP
|
4
4
|
module NodeStore
|
5
|
+
# Wraps sqlite3 database created/maintianed by rippled. Allows client
|
6
|
+
# to query for data stored in sql database.
|
5
7
|
class SQLDB
|
8
|
+
|
9
|
+
# SQL DB intializer
|
10
|
+
#
|
11
|
+
# @param dir [String] directory containing binary nodestore. For consistency
|
12
|
+
# with other nodestore paths this should be set to the directory containing
|
13
|
+
# the actual 'nudb' or 'rocksdb' datafiles, as the sqlite3 databases will be
|
14
|
+
# inferred from the parent directory.
|
6
15
|
def initialize(dir)
|
7
16
|
@dir = dir
|
8
17
|
end
|
9
18
|
|
10
19
|
def ledger_db
|
11
|
-
@ledger_db ||= SQLite3::Database.new File.join(@dir, "ledger.db")
|
20
|
+
@ledger_db ||= SQLite3::Database.new File.join(@dir, "..", "ledger.db")
|
12
21
|
end
|
13
22
|
|
14
23
|
def tx_db
|
15
|
-
@ledger_db ||= SQLite3::Database.new File.join(@dir, "transaction.db")
|
24
|
+
@ledger_db ||= SQLite3::Database.new File.join(@dir, "..", "transaction.db")
|
16
25
|
end
|
17
26
|
|
18
|
-
def
|
19
|
-
|
27
|
+
def ledgers
|
28
|
+
@ledgers ||= Ledgers.new(self)
|
20
29
|
end
|
30
|
+
|
31
|
+
class Ledgers
|
32
|
+
include Enumerable
|
33
|
+
|
34
|
+
def initialize(sql_db)
|
35
|
+
@sql_db = sql_db
|
36
|
+
end
|
37
|
+
|
38
|
+
def between(before, after)
|
39
|
+
@sql_db.ledger_db.execute("select * from ledgers where ClosingTime >= ? and ClosingTime <= ?",
|
40
|
+
before.to_xrp_time,
|
41
|
+
after.to_xrp_time)
|
42
|
+
.collect { |row| from_db(row) }
|
43
|
+
end
|
44
|
+
|
45
|
+
def hash_for_seq(seq)
|
46
|
+
@sql_db.ledger_db.execute("select LedgerHash from ledgers where LedgerSeq = ?", seq).first.first
|
47
|
+
end
|
48
|
+
|
49
|
+
def size
|
50
|
+
@sql_db.ledger_db.execute("select count(*) from ledgers").first.first
|
51
|
+
end
|
52
|
+
|
53
|
+
alias :count :size
|
54
|
+
|
55
|
+
def each
|
56
|
+
all.each do |row|
|
57
|
+
yield row
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def last
|
62
|
+
all.last
|
63
|
+
end
|
64
|
+
|
65
|
+
# TODO: remove memoization, define first(n), last(n) methods
|
66
|
+
def all
|
67
|
+
@all ||= @sql_db.ledger_db.execute("select * from ledgers order by LedgerSeq asc")
|
68
|
+
.collect { |row| from_db(row) }
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def from_db(row)
|
74
|
+
{:hash => row[0],
|
75
|
+
:seq => row[1],
|
76
|
+
:prev_hash => row[2],
|
77
|
+
:total_coins => row[3],
|
78
|
+
:closing_time => row[4].from_xrp_time,
|
79
|
+
:prev_closing_time => row[5].from_xrp_time,
|
80
|
+
:close_time_res => row[6],
|
81
|
+
:close_flags => row[7],
|
82
|
+
:account_set_hash => row[8],
|
83
|
+
:trans_set_hash => row[9]}
|
84
|
+
end
|
85
|
+
end # class Ledgers
|
21
86
|
end # class SQLDB
|
22
87
|
end # module NodeStore
|
23
88
|
end # module XRBP
|
@@ -44,7 +44,7 @@ module XRBP
|
|
44
44
|
sf = sha512.digest(sf)
|
45
45
|
pf = sha512.digest(pf)
|
46
46
|
shared = sf.to_bn ^ pf.to_bn
|
47
|
-
shared = shared.
|
47
|
+
shared = shared.byte_string
|
48
48
|
shared = sha512.digest(shared)[0..31]
|
49
49
|
|
50
50
|
shared = Crypto::Key.sign_digest(node, shared)
|
data/lib/xrbp/version.rb
CHANGED
@@ -1,16 +1,21 @@
|
|
1
1
|
describe XRBP::Crypto do
|
2
2
|
let(:account) { "rDbWJ9C7uExThZYAwV8m6LsZ5YSX3sa6US" }
|
3
|
-
let(:
|
3
|
+
let(:account_id) { 788735140293854337814932116604999410196843811141 }
|
4
|
+
let(:parsed) { [0x8a, 0x28, 0x1b, 0x5e, 0x46, 0xb0, 0x27, 0xc3, 0x70, 0x26, 0xe3, 0x8d, 0xbc, 0x5f, 0x9a, 0xa1, 0x4c, 0x37, 0x51, 0x45].pack("C*") }
|
4
5
|
|
5
6
|
it "generates valid account" do
|
6
7
|
acct = described_class.account
|
7
8
|
expect(described_class.account?(acct[:account])).to be(true)
|
8
9
|
end
|
9
10
|
|
11
|
+
it "returns account id for account" do
|
12
|
+
expect(described_class.account_id(account).to_bn).to eq(account_id)
|
13
|
+
end
|
14
|
+
|
10
15
|
it "parses account" do
|
11
16
|
a = described_class.parse_account(account)
|
12
17
|
expect(a).to_not be_nil
|
13
|
-
expect(a).to eq(
|
18
|
+
expect(a).to eq(parsed)
|
14
19
|
end
|
15
20
|
|
16
21
|
it "does not parse invalid account" do
|
@@ -3,7 +3,70 @@ shared_examples "a database parser" do |opts={}|
|
|
3
3
|
let(:ledger) { {"nt_ledger"=>1, "hp_ledger_master"=>"4c575200", "index"=>47508432, "total_coins"=>18248035087498961665, "parent_hash"=>"C4FAD6EB19F6A6089E7AEBC73AF596DB471305BC0EBB99D9D1414BD4DB8C9D43", "tx_hash"=>"934A5E57C598F0505664F9349DA87FD32AFBE1C315A2CB6CFB5B690AECC6B1A3", "account_hash"=>"FEA269DAAA66C820978AC95F0399ECACA7A3ABAC91402C9FC7961A53D053332F", "parent_close_time"=>Time.parse("2019-05-25T20:12:20Z").utc, "close_time"=>Time.parse("2019-05-25T20:12:21Z").utc, "close_time_resolution"=>10, "close_flags"=>0} }
|
4
4
|
|
5
5
|
let(:tx_key) { ["003b960d5e30ff91a91f7c900509a99a8a6b89441b76158e5ed295ad1d27b0e7"].pack("H*") }
|
6
|
-
let(:tx) { {
|
6
|
+
let(:tx) { {
|
7
|
+
:node=>{
|
8
|
+
:transaction_type=>:Payment,
|
9
|
+
:flags=>2147942400,
|
10
|
+
:sequence=>3366484,
|
11
|
+
:last_ledger_sequence=>47713577,
|
12
|
+
:amount=>XRBP::NodeStore::STAmount.new(:issue => XRBP::NodeStore::Issue.new("XCN", "rPFLkxQk6xUGdGYEykqe7PR25Gr7mLHDc8"), :mantissa => 1000000000000000, :exponent => -11),
|
13
|
+
:fee=>XRBP::NodeStore::STAmount.new(:issue => XRBP::NodeStore.xrp_issue, :mantissa => 11),
|
14
|
+
:send_max=>XRBP::NodeStore::STAmount.new(:issue => XRBP::NodeStore.xrp_issue, :mantissa => 10000000000),
|
15
|
+
:signing_pub_key=>"030ac4f2ba6e1ff86beb234b639918dafdf0675032ae264d2b39641503822373fe",
|
16
|
+
:txn_signature=>"304402207ac9c62a6e8a876e67945edebcd3f6c71c36c95fbbb0ce05a85871d0794b1b8c0220297fe7195beb083a78ff9de4d822b5e4cb42be7e5a8662bcbc2f42c737e264bf",
|
17
|
+
:account=>"rKLpjpCoXgLQQYQyj13zgay73rsgmzNH13",
|
18
|
+
:destination=>"rKLpjpCoXgLQQYQyj13zgay73rsgmzNH13",
|
19
|
+
:paths=>[[
|
20
|
+
{:currency=>"CNY", :issuer=>"rKiCet8SdvWxPXnAgYarFUXMh1zCPz432Y"},
|
21
|
+
{:currency=>"USD", :issuer=>"rhub8VRN55s94qWKDv6jmDy1pUykJzF3wq"},
|
22
|
+
{:currency=>"\x00\x00\x00"},
|
23
|
+
{:currency=>"XCN", :issuer=>"rPFLkxQk6xUGdGYEykqe7PR25Gr7mLHDc8"}
|
24
|
+
],[
|
25
|
+
{:currency=>"USD", :issuer=>"rhub8VRN55s94qWKDv6jmDy1pUykJzF3wq"},
|
26
|
+
{:currency=>"CNY", :issuer=>"rKiCet8SdvWxPXnAgYarFUXMh1zCPz432Y"},
|
27
|
+
{:currency=>"\x00\x00\x00"},
|
28
|
+
{:currency=>"XCN", :issuer=>"rPFLkxQk6xUGdGYEykqe7PR25Gr7mLHDc8"}
|
29
|
+
],[
|
30
|
+
{:currency=>"CNY", :issuer=>"rKiCet8SdvWxPXnAgYarFUXMh1zCPz432Y"},
|
31
|
+
{:currency=>"CNY", :issuer=>"razqQKzJRdB4UxFPWf5NEpEG3WMkmwgcXA"},
|
32
|
+
{:currency=>"\x00\x00\x00"},
|
33
|
+
{:currency=>"XCN", :issuer=>"rPFLkxQk6xUGdGYEykqe7PR25Gr7mLHDc8"}
|
34
|
+
],[
|
35
|
+
{:currency=>"CNY", :issuer=>"razqQKzJRdB4UxFPWf5NEpEG3WMkmwgcXA"},
|
36
|
+
{:currency=>"CNY", :issuer=>"rKiCet8SdvWxPXnAgYarFUXMh1zCPz432Y"},
|
37
|
+
{:currency=>"\x00\x00\x00"},
|
38
|
+
{:currency=>"XCN", :issuer=>"rPFLkxQk6xUGdGYEykqe7PR25Gr7mLHDc8"}
|
39
|
+
],[
|
40
|
+
{:currency=>"CNY", :issuer=>"rKiCet8SdvWxPXnAgYarFUXMh1zCPz432Y"},
|
41
|
+
{:currency=>"EUR", :issuer=>"rhub8VRN55s94qWKDv6jmDy1pUykJzF3wq"},
|
42
|
+
{:currency=>"\x00\x00\x00"},
|
43
|
+
{:currency=>"XCN", :issuer=>"rPFLkxQk6xUGdGYEykqe7PR25Gr7mLHDc8"}
|
44
|
+
],[
|
45
|
+
{:currency=>"EUR", :issuer=>"rhub8VRN55s94qWKDv6jmDy1pUykJzF3wq"},
|
46
|
+
{:currency=>"CNY", :issuer=>"rKiCet8SdvWxPXnAgYarFUXMh1zCPz432Y"},
|
47
|
+
{:currency=>"\x00\x00\x00"},
|
48
|
+
{:currency=>"XCN", :issuer=>"rPFLkxQk6xUGdGYEykqe7PR25Gr7mLHDc8"}]]
|
49
|
+
},:meta=>{
|
50
|
+
:transaction_index=>30,
|
51
|
+
:affected_nodes=>[{
|
52
|
+
:ledger_entry_type=>:account_root,
|
53
|
+
:previous_txn_lgr_seq=>47713575,
|
54
|
+
:previous_txn_id=>"2e397e516ccde852e829d36eb7d0d195dd9a974a188e213ad256c3ae3c131e58",
|
55
|
+
:ledger_index=>"792ba4e4659c27cf3b63f96b34f158748b081cf532f6746a1e3ebd07acba1a0e",
|
56
|
+
:previous_fields=>{
|
57
|
+
:sequence=>3366484,
|
58
|
+
:balance=>XRBP::NodeStore::STAmount.new(:issue => XRBP::NodeStore.xrp_issue, :mantissa => 1920887273)
|
59
|
+
},:final_fields=>{
|
60
|
+
:flags=>0,
|
61
|
+
:sequence=>3366485,
|
62
|
+
:owner_count=>5,
|
63
|
+
:balance=>XRBP::NodeStore::STAmount.new(:issue => XRBP::NodeStore.xrp_issue, :mantissa => 1920887262),
|
64
|
+
:account=>"rKLpjpCoXgLQQYQyj13zgay73rsgmzNH13"
|
65
|
+
}
|
66
|
+
}],
|
67
|
+
:transaction_result=>:tecPATH_DRY},
|
68
|
+
:index=>"5C28E293E88CCEEFBBAB3EF58C1F8C1C02A5194F42A42349597DDCBC86BFEB0D"
|
69
|
+
} }
|
7
70
|
|
8
71
|
let(:ledger_entry_key) { ["002989b414eff398027fce4045f643d68aca440aeea11518a950550ca02c18dd"].pack("H*") }
|
9
72
|
let(:ledger_entry) { {:type=>:account_root, :index=>"9A34C6D1C46168ECE90EB867C78AB2BECE80FAF5D86D09082017E2C89BD68E56", :fields=>{:flags=>0, :sequence=>2, :previous_txn_lgr_seq=>45017187, :owner_count=>0, :previous_txn_id=>"3133839f2401cc9a719778f53319486d11e7ad7ec7891ac083e2aa7eb924516a", :balance=>XRBP::NodeStore::STAmount.new(:issue => XRBP::NodeStore.xrp_issue, :mantissa => 20000000), :account=>"r4HW4bomLvvzA22dACJwUq95ZRr8ZAcXXs"}} }
|