xrbp 0.2.1 → 0.2.2
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 +12 -7
- data/lib/xrbp/core_ext.rb +27 -0
- data/lib/xrbp/crypto/account.rb +28 -3
- data/lib/xrbp/nodestore.rb +6 -0
- data/lib/xrbp/nodestore/amendments.rb +13 -0
- data/lib/xrbp/nodestore/backends/decompressor.rb +8 -6
- data/lib/xrbp/nodestore/backends/nudb.rb +2 -0
- data/lib/xrbp/nodestore/backends/rocksdb.rb +1 -0
- data/lib/xrbp/nodestore/db.rb +5 -387
- data/lib/xrbp/nodestore/fees.rb +19 -0
- data/lib/xrbp/nodestore/format.rb +72 -1
- data/lib/xrbp/nodestore/ledger.rb +272 -0
- data/lib/xrbp/nodestore/parser.rb +407 -0
- data/lib/xrbp/nodestore/protocol.rb +5 -0
- data/lib/xrbp/nodestore/protocol/currency.rb +11 -0
- data/lib/xrbp/nodestore/protocol/indexes.rb +109 -0
- data/lib/xrbp/nodestore/protocol/issue.rb +26 -0
- data/lib/xrbp/nodestore/protocol/quality.rb +10 -0
- data/lib/xrbp/nodestore/protocol/rate.rb +21 -0
- data/lib/xrbp/nodestore/shamap.rb +447 -0
- data/lib/xrbp/nodestore/shamap/errors.rb +8 -0
- data/lib/xrbp/nodestore/shamap/inner_node.rb +98 -0
- data/lib/xrbp/nodestore/shamap/item.rb +14 -0
- data/lib/xrbp/nodestore/shamap/node.rb +49 -0
- data/lib/xrbp/nodestore/shamap/node_factory.rb +120 -0
- data/lib/xrbp/nodestore/shamap/node_id.rb +83 -0
- data/lib/xrbp/nodestore/shamap/tagged_cache.rb +20 -0
- data/lib/xrbp/nodestore/shamap/tree_node.rb +21 -0
- data/lib/xrbp/nodestore/sle.rb +4 -0
- data/lib/xrbp/nodestore/sle/st_account.rb +8 -0
- data/lib/xrbp/nodestore/sle/st_amount.rb +226 -0
- data/lib/xrbp/nodestore/sle/st_ledger_entry.rb +24 -0
- data/lib/xrbp/nodestore/sle/st_object.rb +46 -0
- data/lib/xrbp/nodestore/sqldb.rb +23 -0
- data/lib/xrbp/nodestore/uint.rb +7 -0
- data/lib/xrbp/version.rb +1 -1
- data/spec/xrbp/nodestore/backends/nudb_spec.rb +3 -1
- data/spec/xrbp/nodestore/backends/rocksdb_spec.rb +1 -1
- data/spec/xrbp/nodestore/{backends/db_parser.rb → db_parser.rb} +2 -2
- data/spec/xrbp/nodestore/ledger_access.rb +17 -0
- metadata +30 -3
@@ -0,0 +1,98 @@
|
|
1
|
+
module XRBP
|
2
|
+
class SHAMap
|
3
|
+
# A DB entry which may contain references of up to 16-child
|
4
|
+
# nodes, facilitating abstract tree-like traversal.
|
5
|
+
#
|
6
|
+
# This class simply encapsulates children w/ hashes
|
7
|
+
class InnerNode < Node
|
8
|
+
attr_accessor :depth, :common, :hashes, :is_branch
|
9
|
+
|
10
|
+
def initialize(args={})
|
11
|
+
@v2 = args[:v2]
|
12
|
+
@depth = args[:depth] || 0
|
13
|
+
|
14
|
+
@common = {}
|
15
|
+
@hashes = {}
|
16
|
+
@children = []
|
17
|
+
@is_branch = 0
|
18
|
+
end
|
19
|
+
|
20
|
+
def v2?
|
21
|
+
@v2
|
22
|
+
end
|
23
|
+
|
24
|
+
def inner?
|
25
|
+
true
|
26
|
+
end
|
27
|
+
|
28
|
+
def common_prefix?(key)
|
29
|
+
hd = depth/2
|
30
|
+
0.upto(hd) do |d|
|
31
|
+
return false if common[d] != key[d]
|
32
|
+
end
|
33
|
+
|
34
|
+
return (common[hd] & 0xF0) &&
|
35
|
+
(key[hd] & 0xF0) if depth & 1
|
36
|
+
|
37
|
+
return true
|
38
|
+
end
|
39
|
+
|
40
|
+
# Returns true if node has no children
|
41
|
+
def empty?
|
42
|
+
is_branch == 0
|
43
|
+
end
|
44
|
+
|
45
|
+
# Return true if specified branch is empty,
|
46
|
+
# else false
|
47
|
+
def empty_branch?(branch)
|
48
|
+
(is_branch & (1 << branch)) == 0
|
49
|
+
end
|
50
|
+
|
51
|
+
# Returns hash of child on given branch
|
52
|
+
def child_hash(branch)
|
53
|
+
raise ArgumentError unless branch >= 0 &&
|
54
|
+
branch < 16
|
55
|
+
hashes[branch]
|
56
|
+
end
|
57
|
+
|
58
|
+
# Returns child containing in given branch
|
59
|
+
def child(branch)
|
60
|
+
raise ArgumentError unless branch >= 0 &&
|
61
|
+
branch < 16
|
62
|
+
@children[branch]
|
63
|
+
end
|
64
|
+
|
65
|
+
# Canonicalize and store child node at branch
|
66
|
+
def canonicalize_child(branch, node)
|
67
|
+
raise ArgumentError unless branch >= 0 &&
|
68
|
+
branch < 16
|
69
|
+
raise unless node
|
70
|
+
raise unless node.hash == hashes[branch]
|
71
|
+
|
72
|
+
if @children[branch]
|
73
|
+
return @children[branch]
|
74
|
+
else
|
75
|
+
return @children[branch] = node
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# Update this node's hash from child hashes
|
80
|
+
def update_hash
|
81
|
+
nh = nil
|
82
|
+
|
83
|
+
if is_branch != 0
|
84
|
+
sha512 = OpenSSL::Digest::SHA512.new
|
85
|
+
sha512 << HASH_+PREFIXES[:inner_node]
|
86
|
+
hashes.each { |k,h|
|
87
|
+
sha512 << v
|
88
|
+
}
|
89
|
+
nh = sha512.digest
|
90
|
+
end
|
91
|
+
|
92
|
+
return false if nh == self.hash
|
93
|
+
self.hash = nh
|
94
|
+
return true
|
95
|
+
end
|
96
|
+
end # class InnerNode
|
97
|
+
end # class SHAMap
|
98
|
+
end # module XRBP
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module XRBP
|
2
|
+
class SHAMap
|
3
|
+
# Binary data blog stored in DB w/ key
|
4
|
+
class Item
|
5
|
+
attr_reader :key
|
6
|
+
attr_reader :data
|
7
|
+
|
8
|
+
def initialize(args = {})
|
9
|
+
@key = args[:key]
|
10
|
+
@data = args[:data]
|
11
|
+
end
|
12
|
+
end # class Item
|
13
|
+
end # class SHAMap
|
14
|
+
end # module XRBP
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require_relative './node_factory'
|
2
|
+
|
3
|
+
module XRBP
|
4
|
+
class SHAMap
|
5
|
+
# Base Node class, all entries stored in tree structures
|
6
|
+
# in nodestore DB inherit from this class
|
7
|
+
class Node
|
8
|
+
extend NodeFactory
|
9
|
+
|
10
|
+
attr_accessor :hash
|
11
|
+
|
12
|
+
TYPES = {
|
13
|
+
:error => 0,
|
14
|
+
:infer => 1,
|
15
|
+
:transaction_nm => 2,
|
16
|
+
:transaction_md => 3,
|
17
|
+
:account_state => 4
|
18
|
+
}
|
19
|
+
|
20
|
+
LEAF_TYPES = [
|
21
|
+
:transaction_nm,
|
22
|
+
:transaction_md,
|
23
|
+
:account_state
|
24
|
+
]
|
25
|
+
|
26
|
+
def initialize(args={})
|
27
|
+
@hash = args[:hash]
|
28
|
+
@type = args[:type]
|
29
|
+
@seq = args[:seq]
|
30
|
+
end
|
31
|
+
|
32
|
+
def leaf?
|
33
|
+
LEAF_TYPES.include?(@type)
|
34
|
+
end
|
35
|
+
|
36
|
+
def inner?
|
37
|
+
false
|
38
|
+
end
|
39
|
+
|
40
|
+
def tree_node?
|
41
|
+
false
|
42
|
+
end
|
43
|
+
|
44
|
+
def update_hash
|
45
|
+
raise "abstract: must be called on a subclass"
|
46
|
+
end
|
47
|
+
end # class Node
|
48
|
+
end # class SHAMap
|
49
|
+
end # module XRBP
|
@@ -0,0 +1,120 @@
|
|
1
|
+
module XRBP
|
2
|
+
class SHAMap
|
3
|
+
module NodeFactory
|
4
|
+
# See rippled::SHAMapAbstractNode::make
|
5
|
+
def make(node, seq, format, hash, hash_valid)
|
6
|
+
node_id = NodeID.new
|
7
|
+
|
8
|
+
if format == :wire
|
9
|
+
# TODO
|
10
|
+
|
11
|
+
elsif format == :prefix
|
12
|
+
raise if node.size < 4
|
13
|
+
|
14
|
+
prefix = node[0].ord
|
15
|
+
prefix <<= 8
|
16
|
+
prefix |= node[1].ord
|
17
|
+
prefix <<= 8
|
18
|
+
prefix |= node[2].ord
|
19
|
+
prefix <<= 8
|
20
|
+
prefix |= node[3].ord
|
21
|
+
prefix = prefix.to_s(16).upcase
|
22
|
+
|
23
|
+
s = node[4..-1]
|
24
|
+
|
25
|
+
if prefix == NodeStore::Format::HASH_PREFIXES[:tx_id]
|
26
|
+
sha512 = OpenSSL::Digest::SHA512.new
|
27
|
+
sha512 << NodeStore::Format::HASH_PREFIXES[:tx_id]
|
28
|
+
sta512 << node
|
29
|
+
key = sha512.digest[0..31]
|
30
|
+
|
31
|
+
item = Item.new(:key => key,
|
32
|
+
:data => node)
|
33
|
+
|
34
|
+
tree_node = {:item => item,
|
35
|
+
:seq => seq,
|
36
|
+
:type => :transaction_nm}
|
37
|
+
tree_node[:hash] = hash if hash_valid
|
38
|
+
|
39
|
+
return TreeNode.new(tree_node)
|
40
|
+
|
41
|
+
elsif prefix == NodeStore::Format::HASH_PREFIXES[:leaf_node]
|
42
|
+
raise "short PLN node" if s.size < 32
|
43
|
+
|
44
|
+
u = s[-32..-1]
|
45
|
+
s = s[0..-33]
|
46
|
+
raise "invalid PLN node" if u.zero?
|
47
|
+
|
48
|
+
item = Item.new(:key => u,
|
49
|
+
:data => s)
|
50
|
+
|
51
|
+
tree_node = {:item => item,
|
52
|
+
:seq => seq,
|
53
|
+
:type => :account_state}
|
54
|
+
tree_node[:hash] = hash if hash_valid
|
55
|
+
|
56
|
+
return TreeNode.new(tree_node)
|
57
|
+
|
58
|
+
elsif (prefix == NodeStore::Format::HASH_PREFIXES[:inner_node]) ||
|
59
|
+
(prefix == NodeStore::Format::HASH_PREFIXES[:inner_node_v2])
|
60
|
+
len = s.size
|
61
|
+
isv2 = prefix == NodeStore::Format::HASH_PREFIXES[:inner_node_v2]
|
62
|
+
|
63
|
+
raise "invalid PIN node" if len < 512 ||
|
64
|
+
(!isv2 && (len != 512)) ||
|
65
|
+
( isv2 && (len == 512))
|
66
|
+
|
67
|
+
ret = InnerNode.new :v2 => isv2
|
68
|
+
|
69
|
+
0.upto(15) { |i|
|
70
|
+
ret.hashes[i] = s[i*32...(i+1)*32]
|
71
|
+
ret.is_branch |= (1 << i) unless ret.hashes[i].zero?
|
72
|
+
}
|
73
|
+
|
74
|
+
if isv2
|
75
|
+
ret.depth = s[512]
|
76
|
+
n = (ret.depth + 1)/2
|
77
|
+
raise "invalid PIN node" if len != 512 + 1 + n
|
78
|
+
|
79
|
+
0.upto(n-1) { |i|
|
80
|
+
ret.common << s[512+1+i]
|
81
|
+
}
|
82
|
+
end
|
83
|
+
|
84
|
+
if hash_valid
|
85
|
+
ret.hash = hash
|
86
|
+
else
|
87
|
+
ret.update_hash
|
88
|
+
end
|
89
|
+
|
90
|
+
return ret
|
91
|
+
|
92
|
+
elsif prefix == NodeStore::Format::HASH_PREFIXES[:tx_node]
|
93
|
+
# transaction with metadata
|
94
|
+
raise "short TXN node" if s.size < 32
|
95
|
+
|
96
|
+
tx_id = s[-32..-1]
|
97
|
+
# XXX: tx_id is last field in binary transaction, keep so
|
98
|
+
# it can be parsed w/ other fields later:
|
99
|
+
#s = s[0..-33]
|
100
|
+
|
101
|
+
item = Item.new(:key => tx_id,
|
102
|
+
:data => s)
|
103
|
+
|
104
|
+
tree_node = {:item => item,
|
105
|
+
:seq => seq,
|
106
|
+
:type => :transaction_md}
|
107
|
+
tree_node[:hash] = hash if hash_valid
|
108
|
+
|
109
|
+
return TreeNode.new(tree_node)
|
110
|
+
|
111
|
+
else
|
112
|
+
raise "Unknown prefix #{prefix}"
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
raise "Unknown format"
|
117
|
+
end
|
118
|
+
end # module NodeFactory
|
119
|
+
end # class SHAMap
|
120
|
+
end # module XRBP
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module XRBP
|
2
|
+
class SHAMap
|
3
|
+
# Encapsulates node key to allow for tree traversal.
|
4
|
+
#
|
5
|
+
# Provides branch extraction/generation logic.
|
6
|
+
# Since branch is between 0-15, only a nibble (4bits)
|
7
|
+
# are needed to store. Thus each char (8bits) can describe
|
8
|
+
# 2 tree branches
|
9
|
+
class NodeID
|
10
|
+
attr_reader :depth, :key
|
11
|
+
|
12
|
+
def initialize(args={})
|
13
|
+
@depth ||= args[:depth] || 0
|
14
|
+
@key ||= args[:key] || NodeStore.uint256
|
15
|
+
end
|
16
|
+
|
17
|
+
MASK_SIZE = 65
|
18
|
+
|
19
|
+
# Masks corresponding to each tree level.
|
20
|
+
# Used to calculate inner node hash for
|
21
|
+
# tree level:
|
22
|
+
# inner node = lookup key & mask
|
23
|
+
def masks
|
24
|
+
@masks ||= begin
|
25
|
+
masks = Array.new(MASK_SIZE)
|
26
|
+
|
27
|
+
i = 0
|
28
|
+
selector = NodeStore.uint256
|
29
|
+
while(i < MASK_SIZE-1)
|
30
|
+
masks[i] = String.new(selector)
|
31
|
+
selector[i / 2] = 0xF0.chr
|
32
|
+
masks[i+1] = String.new(selector)
|
33
|
+
selector[i / 2] = 0xFF.chr
|
34
|
+
i += 2
|
35
|
+
end
|
36
|
+
masks[MASK_SIZE-1] = selector
|
37
|
+
|
38
|
+
masks
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Return mask for current tree depth
|
43
|
+
def mask
|
44
|
+
@mask ||= masks[depth]
|
45
|
+
end
|
46
|
+
|
47
|
+
# Return branch number of specified hash.
|
48
|
+
def select_branch(hash)
|
49
|
+
#if RIPPLE_VERIFY_NODEOBJECT_KEYS
|
50
|
+
raise if depth >= 64
|
51
|
+
raise if (hash.to_bn & mask.to_bn) != key.to_bn
|
52
|
+
#end
|
53
|
+
|
54
|
+
# Extract hash byte at local node depth
|
55
|
+
br = hash[depth / 2].ord
|
56
|
+
|
57
|
+
# Reduce to relevant nibble
|
58
|
+
if (depth & 1) == 1
|
59
|
+
br &= 0xf
|
60
|
+
else
|
61
|
+
br >>= 4
|
62
|
+
end
|
63
|
+
|
64
|
+
raise unless (br >= 0) && (br < 16)
|
65
|
+
br
|
66
|
+
end
|
67
|
+
|
68
|
+
# Return NodeID for specified branch under this one.
|
69
|
+
def child_node_id(branch)
|
70
|
+
raise unless branch >= 0 && branch < 16
|
71
|
+
raise unless depth < 64
|
72
|
+
|
73
|
+
# Copy local key and assign branch number to
|
74
|
+
# nibble in byte at local depth
|
75
|
+
child = key.unpack("C*")
|
76
|
+
child[depth/2] |= ((depth & 1) == 1) ? branch : (branch << 4)
|
77
|
+
|
78
|
+
NodeID.new :depth => (depth + 1),
|
79
|
+
:key => child.pack("C*")
|
80
|
+
end
|
81
|
+
end # class NodeID
|
82
|
+
end # class SHAMap
|
83
|
+
end # module XRBP
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module XRBP
|
2
|
+
class SHAMap
|
3
|
+
# Internal node caching mechanism.
|
4
|
+
#
|
5
|
+
# TODO timeout mechanism, metrics
|
6
|
+
class TaggedCache
|
7
|
+
def initialize
|
8
|
+
@cache = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def fetch(key)
|
12
|
+
@cache[key]
|
13
|
+
end
|
14
|
+
|
15
|
+
def canonicalize(key, node)
|
16
|
+
@cache[key] = node
|
17
|
+
end
|
18
|
+
end # class TaggedCache
|
19
|
+
end # class SHAMap
|
20
|
+
end # module XRBP
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module XRBP
|
2
|
+
class SHAMap
|
3
|
+
# Terminating tree node referencing concrete data
|
4
|
+
class TreeNode < Node
|
5
|
+
attr_reader :item
|
6
|
+
|
7
|
+
def initialize(args={})
|
8
|
+
super
|
9
|
+
@item = args[:item]
|
10
|
+
end
|
11
|
+
|
12
|
+
def tree_node?
|
13
|
+
true
|
14
|
+
end
|
15
|
+
|
16
|
+
def peek_item
|
17
|
+
item
|
18
|
+
end
|
19
|
+
end # class TreeNode
|
20
|
+
end # class SHAMap
|
21
|
+
end # module XRBP
|
@@ -0,0 +1,226 @@
|
|
1
|
+
module XRBP
|
2
|
+
module NodeStore
|
3
|
+
# Serialized Amount Representation
|
4
|
+
class STAmount
|
5
|
+
# see: https://github.com/ripple/rippled/blob/b53fda1e1a7f4d09b766724274329df1c29988ab/src/ripple/protocol/STAmount.h#L67
|
6
|
+
MIN_VAL = 1000000000000000
|
7
|
+
|
8
|
+
attr_reader :mantissa, :exponent, :neg
|
9
|
+
attr_accessor :issue
|
10
|
+
|
11
|
+
alias :value :mantissa
|
12
|
+
alias :offset :exponent
|
13
|
+
|
14
|
+
def self.zero(args={})
|
15
|
+
STAmount.new args.merge({:mantissa => 0})
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.from_quality(rate)
|
19
|
+
return STAmount.new(:issue => NodeStore.no_issue) if rate == 0
|
20
|
+
|
21
|
+
mantissa = rate & ~(255 << (64 - 8))
|
22
|
+
exponent = (rate >> (64 - 8)) - 100
|
23
|
+
|
24
|
+
return STAmount.new(:issue => NodeStore.no_issue,
|
25
|
+
:mantissa => mantissa,
|
26
|
+
:exponent => exponent)
|
27
|
+
end
|
28
|
+
|
29
|
+
def initialize(args={})
|
30
|
+
@issue = args[:issue]
|
31
|
+
@mantissa = args[:mantissa] || 0
|
32
|
+
@exponent = args[:exponent] || 0
|
33
|
+
@neg = !!args[:neg]
|
34
|
+
end
|
35
|
+
|
36
|
+
def native?
|
37
|
+
@issue.xrp?
|
38
|
+
end
|
39
|
+
|
40
|
+
def zero?
|
41
|
+
@mantissa == 0
|
42
|
+
end
|
43
|
+
|
44
|
+
def clear
|
45
|
+
# see: https://github.com/ripple/rippled/blob/b53fda1e1a7f4d09b766724274329df1c29988ab/src/ripple/protocol/STAmount.h#L224
|
46
|
+
@exponent = native? ? 0 : -100
|
47
|
+
|
48
|
+
@neg = false
|
49
|
+
@mantissa = 0
|
50
|
+
end
|
51
|
+
|
52
|
+
def negate!
|
53
|
+
return if zero?
|
54
|
+
@neg = !@neg
|
55
|
+
end
|
56
|
+
|
57
|
+
def sn_value
|
58
|
+
neg ? (-mantissa) : mantissa
|
59
|
+
end
|
60
|
+
|
61
|
+
###
|
62
|
+
|
63
|
+
# In drops!
|
64
|
+
def xrp_amount
|
65
|
+
neg ? (-value) : value
|
66
|
+
end
|
67
|
+
|
68
|
+
alias :drops :xrp_amount
|
69
|
+
|
70
|
+
def iou_amount
|
71
|
+
(neg ? -1 : 1) * mantissa * 10 ** (exponent-97)
|
72
|
+
end
|
73
|
+
|
74
|
+
###
|
75
|
+
|
76
|
+
def +(v)
|
77
|
+
e1 = exponent
|
78
|
+
e2 = v.exponent
|
79
|
+
|
80
|
+
m1 = mantissa
|
81
|
+
m2 = v.mantissa
|
82
|
+
|
83
|
+
m1 *= -1 if neg
|
84
|
+
m2 *= -1 if v.neg
|
85
|
+
|
86
|
+
while e1 < e2
|
87
|
+
m1 /= 10
|
88
|
+
e1 += 1
|
89
|
+
end
|
90
|
+
|
91
|
+
while e2 < e1
|
92
|
+
m2 /= 10
|
93
|
+
e2 += 1
|
94
|
+
end
|
95
|
+
|
96
|
+
m = m1 + m2
|
97
|
+
return STAmount.new :issue => issue if m >= -10 && m <= 10
|
98
|
+
return STAmount.new :mantissa => m,
|
99
|
+
:exponent => e1,
|
100
|
+
:issue => issue if m >= 0
|
101
|
+
return STAmount.new :mantissa => -m,
|
102
|
+
:exponent => e1,
|
103
|
+
:issue => issue
|
104
|
+
end
|
105
|
+
|
106
|
+
def -(v)
|
107
|
+
self + (-v)
|
108
|
+
end
|
109
|
+
|
110
|
+
def /(v)
|
111
|
+
if v.is_a?(Rate)
|
112
|
+
return self if v == Rate.parity
|
113
|
+
return self / v.to_amount
|
114
|
+
end
|
115
|
+
|
116
|
+
raise "divide by zero" if v.zero?
|
117
|
+
return STAmount.new :issue => issue
|
118
|
+
|
119
|
+
nm = mantissa
|
120
|
+
dm = v.mantissa
|
121
|
+
|
122
|
+
ne = exponent
|
123
|
+
de = v.exponent
|
124
|
+
|
125
|
+
if native?
|
126
|
+
while nm < MIN_VAL
|
127
|
+
nm *= 10
|
128
|
+
ne -= 1
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
if v.native?
|
133
|
+
while dm < MIN_VAL
|
134
|
+
dm *= 10
|
135
|
+
de -= 1
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# see note: https://github.com/ripple/rippled/blob/b53fda1e1a7f4d09b766724274329df1c29988ab/src/ripple/protocol/impl/STAmount.cpp#L1075
|
140
|
+
STAmount.new :issue => issue,
|
141
|
+
:mantissa => (nm * 10**17)/dm,
|
142
|
+
:exponent => (ne - de - 17),
|
143
|
+
:neg => (neg != v.neg)
|
144
|
+
end
|
145
|
+
|
146
|
+
def *(o)
|
147
|
+
return STAmount.new :issue => issue if zero? || o.zero?
|
148
|
+
|
149
|
+
if native?
|
150
|
+
min = sn_value < o.sn_value ? sn_value : o.sn_value
|
151
|
+
max = sn_value < o.sn_value ? o.sn_value : sn_value
|
152
|
+
|
153
|
+
return STAmount.new :mantissa => min * max
|
154
|
+
end
|
155
|
+
|
156
|
+
m1 = mantissa
|
157
|
+
m2 = o.mantissa
|
158
|
+
e1 = exponent
|
159
|
+
e2 = o.exponent
|
160
|
+
|
161
|
+
if native?
|
162
|
+
while nm < MIN_VAL
|
163
|
+
m1 *= 10
|
164
|
+
e1 -= 1
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
if o.native?
|
169
|
+
while dm < MIN_VAL
|
170
|
+
m2 *= 10
|
171
|
+
e2 -= 1
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
# see note: https://github.com/ripple/rippled/blob/b53fda1e1a7f4d09b766724274329df1c29988ab/src/ripple/protocol/impl/STAmount.cpp#L1131
|
176
|
+
STAmount.new :issue => issue,
|
177
|
+
:mantissa => (m1 * m2)/(10**14),
|
178
|
+
:exponent => (e1 + e2 + 14),
|
179
|
+
:neg => (neg != o.neg)
|
180
|
+
end
|
181
|
+
|
182
|
+
def -@
|
183
|
+
STAmount.new(:mantissa => mantissa,
|
184
|
+
:exponent => exponent,
|
185
|
+
:issue => issue,
|
186
|
+
:neg => !neg)
|
187
|
+
end
|
188
|
+
|
189
|
+
def <(o)
|
190
|
+
return neg if neg && !o.neg
|
191
|
+
if mantissa == 0
|
192
|
+
return false if o.neg
|
193
|
+
return o.mantissa != 0
|
194
|
+
end
|
195
|
+
|
196
|
+
return false if o.mantissa == 0
|
197
|
+
return neg if exponent > o.exponent
|
198
|
+
return !neg if exponent < o.exponent
|
199
|
+
return neg if mantissa > o.mantissa
|
200
|
+
return !neg if mantissa < o.mantissa
|
201
|
+
|
202
|
+
return false
|
203
|
+
end
|
204
|
+
|
205
|
+
def >=(o)
|
206
|
+
!(self < o)
|
207
|
+
end
|
208
|
+
|
209
|
+
def >(o)
|
210
|
+
self >= o && self != o
|
211
|
+
end
|
212
|
+
|
213
|
+
def ==(o)
|
214
|
+
neg == o.neg &&
|
215
|
+
mantissa == o.mantissa &&
|
216
|
+
exponent == o.exponent
|
217
|
+
end
|
218
|
+
|
219
|
+
def <=>(o)
|
220
|
+
return 0 if self == o
|
221
|
+
return -1 if self < o
|
222
|
+
return 1 if self > o
|
223
|
+
end
|
224
|
+
end # class STAmount
|
225
|
+
end # module NodeStore
|
226
|
+
end # module XRBP
|