xrbp 0.2.1 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|