tapyrus 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +12 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +100 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/exe/tapyrusrb-cli +5 -0
- data/exe/tapyrusrbd +41 -0
- data/lib/openassets/marker_output.rb +20 -0
- data/lib/openassets/payload.rb +54 -0
- data/lib/openassets/util.rb +28 -0
- data/lib/openassets.rb +9 -0
- data/lib/tapyrus/base58.rb +38 -0
- data/lib/tapyrus/block.rb +77 -0
- data/lib/tapyrus/block_header.rb +88 -0
- data/lib/tapyrus/bloom_filter.rb +78 -0
- data/lib/tapyrus/chain_params.rb +90 -0
- data/lib/tapyrus/chainparams/mainnet.yml +41 -0
- data/lib/tapyrus/chainparams/regtest.yml +38 -0
- data/lib/tapyrus/chainparams/testnet.yml +41 -0
- data/lib/tapyrus/constants.rb +195 -0
- data/lib/tapyrus/descriptor.rb +147 -0
- data/lib/tapyrus/ext_key.rb +337 -0
- data/lib/tapyrus/key.rb +296 -0
- data/lib/tapyrus/key_path.rb +26 -0
- data/lib/tapyrus/logger.rb +42 -0
- data/lib/tapyrus/merkle_tree.rb +149 -0
- data/lib/tapyrus/message/addr.rb +35 -0
- data/lib/tapyrus/message/base.rb +28 -0
- data/lib/tapyrus/message/block.rb +46 -0
- data/lib/tapyrus/message/block_transaction_request.rb +45 -0
- data/lib/tapyrus/message/block_transactions.rb +31 -0
- data/lib/tapyrus/message/block_txn.rb +27 -0
- data/lib/tapyrus/message/cmpct_block.rb +42 -0
- data/lib/tapyrus/message/error.rb +10 -0
- data/lib/tapyrus/message/fee_filter.rb +27 -0
- data/lib/tapyrus/message/filter_add.rb +28 -0
- data/lib/tapyrus/message/filter_clear.rb +17 -0
- data/lib/tapyrus/message/filter_load.rb +39 -0
- data/lib/tapyrus/message/get_addr.rb +17 -0
- data/lib/tapyrus/message/get_block_txn.rb +27 -0
- data/lib/tapyrus/message/get_blocks.rb +29 -0
- data/lib/tapyrus/message/get_data.rb +21 -0
- data/lib/tapyrus/message/get_headers.rb +28 -0
- data/lib/tapyrus/message/header_and_short_ids.rb +57 -0
- data/lib/tapyrus/message/headers.rb +35 -0
- data/lib/tapyrus/message/headers_parser.rb +24 -0
- data/lib/tapyrus/message/inv.rb +21 -0
- data/lib/tapyrus/message/inventories_parser.rb +23 -0
- data/lib/tapyrus/message/inventory.rb +51 -0
- data/lib/tapyrus/message/mem_pool.rb +17 -0
- data/lib/tapyrus/message/merkle_block.rb +42 -0
- data/lib/tapyrus/message/network_addr.rb +63 -0
- data/lib/tapyrus/message/not_found.rb +21 -0
- data/lib/tapyrus/message/ping.rb +30 -0
- data/lib/tapyrus/message/pong.rb +26 -0
- data/lib/tapyrus/message/prefilled_tx.rb +29 -0
- data/lib/tapyrus/message/reject.rb +46 -0
- data/lib/tapyrus/message/send_cmpct.rb +43 -0
- data/lib/tapyrus/message/send_headers.rb +16 -0
- data/lib/tapyrus/message/tx.rb +30 -0
- data/lib/tapyrus/message/ver_ack.rb +17 -0
- data/lib/tapyrus/message/version.rb +69 -0
- data/lib/tapyrus/message.rb +70 -0
- data/lib/tapyrus/mnemonic/wordlist/chinese_simplified.txt +2048 -0
- data/lib/tapyrus/mnemonic/wordlist/chinese_traditional.txt +2048 -0
- data/lib/tapyrus/mnemonic/wordlist/english.txt +2048 -0
- data/lib/tapyrus/mnemonic/wordlist/french.txt +2048 -0
- data/lib/tapyrus/mnemonic/wordlist/italian.txt +2048 -0
- data/lib/tapyrus/mnemonic/wordlist/japanese.txt +2048 -0
- data/lib/tapyrus/mnemonic/wordlist/spanish.txt +2048 -0
- data/lib/tapyrus/mnemonic.rb +77 -0
- data/lib/tapyrus/network/connection.rb +73 -0
- data/lib/tapyrus/network/message_handler.rb +241 -0
- data/lib/tapyrus/network/peer.rb +223 -0
- data/lib/tapyrus/network/peer_discovery.rb +42 -0
- data/lib/tapyrus/network/pool.rb +135 -0
- data/lib/tapyrus/network.rb +13 -0
- data/lib/tapyrus/node/cli.rb +112 -0
- data/lib/tapyrus/node/configuration.rb +38 -0
- data/lib/tapyrus/node/spv.rb +79 -0
- data/lib/tapyrus/node.rb +7 -0
- data/lib/tapyrus/opcodes.rb +178 -0
- data/lib/tapyrus/out_point.rb +44 -0
- data/lib/tapyrus/rpc/http_server.rb +65 -0
- data/lib/tapyrus/rpc/request_handler.rb +150 -0
- data/lib/tapyrus/rpc/tapyrus_core_client.rb +72 -0
- data/lib/tapyrus/rpc.rb +7 -0
- data/lib/tapyrus/script/multisig.rb +92 -0
- data/lib/tapyrus/script/script.rb +551 -0
- data/lib/tapyrus/script/script_error.rb +111 -0
- data/lib/tapyrus/script/script_interpreter.rb +668 -0
- data/lib/tapyrus/script/tx_checker.rb +81 -0
- data/lib/tapyrus/script_witness.rb +38 -0
- data/lib/tapyrus/secp256k1/native.rb +174 -0
- data/lib/tapyrus/secp256k1/ruby.rb +123 -0
- data/lib/tapyrus/secp256k1.rb +12 -0
- data/lib/tapyrus/slip39/share.rb +122 -0
- data/lib/tapyrus/slip39/sss.rb +245 -0
- data/lib/tapyrus/slip39/wordlist/english.txt +1024 -0
- data/lib/tapyrus/slip39.rb +93 -0
- data/lib/tapyrus/store/chain_entry.rb +67 -0
- data/lib/tapyrus/store/db/level_db.rb +98 -0
- data/lib/tapyrus/store/db.rb +9 -0
- data/lib/tapyrus/store/spv_chain.rb +101 -0
- data/lib/tapyrus/store.rb +9 -0
- data/lib/tapyrus/tx.rb +347 -0
- data/lib/tapyrus/tx_in.rb +89 -0
- data/lib/tapyrus/tx_out.rb +74 -0
- data/lib/tapyrus/util.rb +133 -0
- data/lib/tapyrus/validation.rb +115 -0
- data/lib/tapyrus/version.rb +3 -0
- data/lib/tapyrus/wallet/account.rb +151 -0
- data/lib/tapyrus/wallet/base.rb +162 -0
- data/lib/tapyrus/wallet/db.rb +81 -0
- data/lib/tapyrus/wallet/master_key.rb +110 -0
- data/lib/tapyrus/wallet.rb +8 -0
- data/lib/tapyrus.rb +219 -0
- data/tapyrusrb.conf.sample +0 -0
- data/tapyrusrb.gemspec +47 -0
- metadata +451 -0
@@ -0,0 +1,93 @@
|
|
1
|
+
module Tapyrus
|
2
|
+
module SLIP39
|
3
|
+
|
4
|
+
WORDS = File.readlines("#{__dir__}/slip39/wordlist/english.txt").map(&:strip)
|
5
|
+
|
6
|
+
module_function
|
7
|
+
|
8
|
+
def bits_to_bytes(n)
|
9
|
+
(n + 7) / 8
|
10
|
+
end
|
11
|
+
|
12
|
+
def bits_to_words(n)
|
13
|
+
(n + RADIX_BITS - 1) / RADIX_BITS
|
14
|
+
end
|
15
|
+
|
16
|
+
# The length of the radix in bits.
|
17
|
+
RADIX_BITS = 10
|
18
|
+
# The number of words in the wordlist.
|
19
|
+
RADIX = 2 ** RADIX_BITS
|
20
|
+
# The length of the random identifier in bits.
|
21
|
+
ID_LENGTH_BITS = 15
|
22
|
+
# The length of the iteration exponent in bits.
|
23
|
+
ITERATION_EXP_LENGTH_BITS = 5
|
24
|
+
# The length of the random identifier and iteration exponent in words.
|
25
|
+
ID_EXP_LENGTH_WORDS = bits_to_words(ID_LENGTH_BITS + ITERATION_EXP_LENGTH_BITS)
|
26
|
+
# The maximum number of shares that can be created.
|
27
|
+
MAX_SHARE_COUNT = 16
|
28
|
+
# The length of the RS1024 checksum in words.
|
29
|
+
CHECKSUM_LENGTH_WORDS = 3
|
30
|
+
# The length of the digest of the shared secret in bytes.
|
31
|
+
DIGEST_LENGTH_BYTES = 4
|
32
|
+
# The customization string used in the RS1024 checksum and in the PBKDF2 salt.
|
33
|
+
CUSTOMIZATION_STRING = 'shamir'.bytes
|
34
|
+
# The length of the mnemonic in words without the share value.
|
35
|
+
METADATA_LENGTH_WORDS = ID_EXP_LENGTH_WORDS + 2 + CHECKSUM_LENGTH_WORDS
|
36
|
+
# The minimum allowed entropy of the master secret.
|
37
|
+
MIN_STRENGTH_BITS = 128
|
38
|
+
# The minimum allowed length of the mnemonic in words.
|
39
|
+
MIN_MNEMONIC_LENGTH_WORDS = METADATA_LENGTH_WORDS + bits_to_words(MIN_STRENGTH_BITS)
|
40
|
+
# The minimum number of iterations to use in PBKDF2.
|
41
|
+
BASE_ITERATION_COUNT = 10000
|
42
|
+
# The number of rounds to use in the Feistel cipher.
|
43
|
+
ROUND_COUNT = 4
|
44
|
+
# The index of the share containing the shared secret.
|
45
|
+
SECRET_INDEX = 255
|
46
|
+
# The index of the share containing the digest of the shared secret.
|
47
|
+
DIGEST_INDEX = 254
|
48
|
+
|
49
|
+
EXP_TABLE = [
|
50
|
+
1, 3, 5, 15, 17, 51, 85, 255, 26, 46, 114, 150, 161, 248, 19,
|
51
|
+
53, 95, 225, 56, 72, 216, 115, 149, 164, 247, 2, 6, 10, 30, 34,
|
52
|
+
102, 170, 229, 52, 92, 228, 55, 89, 235, 38, 106, 190, 217, 112, 144,
|
53
|
+
171, 230, 49, 83, 245, 4, 12, 20, 60, 68, 204, 79, 209, 104, 184,
|
54
|
+
211, 110, 178, 205, 76, 212, 103, 169, 224, 59, 77, 215, 98, 166, 241,
|
55
|
+
8, 24, 40, 120, 136, 131, 158, 185, 208, 107, 189, 220, 127, 129, 152,
|
56
|
+
179, 206, 73, 219, 118, 154, 181, 196, 87, 249, 16, 48, 80, 240, 11,
|
57
|
+
29, 39, 105, 187, 214, 97, 163, 254, 25, 43, 125, 135, 146, 173, 236,
|
58
|
+
47, 113, 147, 174, 233, 32, 96, 160, 251, 22, 58, 78, 210, 109, 183,
|
59
|
+
194, 93, 231, 50, 86, 250, 21, 63, 65, 195, 94, 226, 61, 71, 201,
|
60
|
+
64, 192, 91, 237, 44, 116, 156, 191, 218, 117, 159, 186, 213, 100, 172,
|
61
|
+
239, 42, 126, 130, 157, 188, 223, 122, 142, 137, 128, 155, 182, 193, 88,
|
62
|
+
232, 35, 101, 175, 234, 37, 111, 177, 200, 67, 197, 84, 252, 31, 33,
|
63
|
+
99, 165, 244, 7, 9, 27, 45, 119, 153, 176, 203, 70, 202, 69, 207,
|
64
|
+
74, 222, 121, 139, 134, 145, 168, 227, 62, 66, 198, 81, 243, 14, 18,
|
65
|
+
54, 90, 238, 41, 123, 141, 140, 143, 138, 133, 148, 167, 242, 13, 23,
|
66
|
+
57, 75, 221, 124, 132, 151, 162, 253, 28, 36, 108, 180, 199, 82, 246
|
67
|
+
]
|
68
|
+
|
69
|
+
LOG_TABLE = [
|
70
|
+
0, 0, 25, 1, 50, 2, 26, 198, 75, 199, 27, 104, 51, 238, 223, 3,
|
71
|
+
100, 4, 224, 14, 52, 141, 129, 239, 76, 113, 8, 200, 248, 105, 28,
|
72
|
+
193, 125, 194, 29, 181, 249, 185, 39, 106, 77, 228, 166, 114, 154, 201,
|
73
|
+
9, 120, 101, 47, 138, 5, 33, 15, 225, 36, 18, 240, 130, 69, 53,
|
74
|
+
147, 218, 142, 150, 143, 219, 189, 54, 208, 206, 148, 19, 92, 210, 241,
|
75
|
+
64, 70, 131, 56, 102, 221, 253, 48, 191, 6, 139, 98, 179, 37, 226,
|
76
|
+
152, 34, 136, 145, 16, 126, 110, 72, 195, 163, 182, 30, 66, 58, 107,
|
77
|
+
40, 84, 250, 133, 61, 186, 43, 121, 10, 21, 155, 159, 94, 202, 78,
|
78
|
+
212, 172, 229, 243, 115, 167, 87, 175, 88, 168, 80, 244, 234, 214, 116,
|
79
|
+
79, 174, 233, 213, 231, 230, 173, 232, 44, 215, 117, 122, 235, 22, 11,
|
80
|
+
245, 89, 203, 95, 176, 156, 169, 81, 160, 127, 12, 246, 111, 23, 196,
|
81
|
+
73, 236, 216, 67, 31, 45, 164, 118, 123, 183, 204, 187, 62, 90, 251,
|
82
|
+
96, 177, 134, 59, 82, 161, 108, 170, 85, 41, 157, 151, 178, 135, 144,
|
83
|
+
97, 190, 220, 252, 188, 149, 207, 205, 55, 63, 91, 209, 83, 57, 132,
|
84
|
+
60, 65, 162, 109, 71, 20, 42, 158, 93, 86, 242, 211, 171, 68, 17, 146,
|
85
|
+
217, 35, 32, 46, 137, 180, 124, 184, 38, 119, 153, 227, 165, 103, 74, 237,
|
86
|
+
222, 197, 49, 254, 24, 13, 99, 140, 128, 192, 247, 112, 7
|
87
|
+
]
|
88
|
+
|
89
|
+
autoload :SSS, 'tapyrus/slip39/sss'
|
90
|
+
autoload :Share, 'tapyrus/slip39/share'
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Tapyrus
|
2
|
+
module Store
|
3
|
+
|
4
|
+
# wrap a block header object with extra data.
|
5
|
+
class ChainEntry
|
6
|
+
|
7
|
+
attr_reader :header
|
8
|
+
attr_reader :height
|
9
|
+
|
10
|
+
# @param [Tapyrus::BlockHeader] header a block header.
|
11
|
+
# @param [Integer] height a block height.
|
12
|
+
def initialize(header, height)
|
13
|
+
@header = header
|
14
|
+
@height = height
|
15
|
+
end
|
16
|
+
|
17
|
+
# get database key
|
18
|
+
def key
|
19
|
+
Tapyrus::Store::KEY_PREFIX[:entry] + header.block_hash
|
20
|
+
end
|
21
|
+
|
22
|
+
def hash
|
23
|
+
header.hash
|
24
|
+
end
|
25
|
+
|
26
|
+
# block hash
|
27
|
+
def block_hash
|
28
|
+
header.block_hash
|
29
|
+
end
|
30
|
+
|
31
|
+
# previous block hash
|
32
|
+
def prev_hash
|
33
|
+
header.prev_hash
|
34
|
+
end
|
35
|
+
|
36
|
+
# whether genesis block
|
37
|
+
def genesis?
|
38
|
+
Tapyrus.chain_params.genesis_block.header == header
|
39
|
+
end
|
40
|
+
|
41
|
+
# @param [String] payload a payload with binary format.
|
42
|
+
def self.parse_from_payload(payload)
|
43
|
+
buf = StringIO.new(payload)
|
44
|
+
len = Tapyrus.unpack_var_int_from_io(buf)
|
45
|
+
height = buf.read(len).reverse.bth.to_i(16)
|
46
|
+
new(Tapyrus::BlockHeader.parse_from_payload(buf.read(80)), height)
|
47
|
+
end
|
48
|
+
|
49
|
+
# build next block +StoredBlock+ instance.
|
50
|
+
# @param [Tapyrus::BlockHeader] next_block a next block candidate header.
|
51
|
+
# @return [Tapyrus::Store::ChainEntry] a next stored block (not saved).
|
52
|
+
def build_next_block(next_block)
|
53
|
+
ChainEntry.new(next_block, height + 1)
|
54
|
+
end
|
55
|
+
|
56
|
+
# generate payload
|
57
|
+
def to_payload
|
58
|
+
height_value = height.to_even_length_hex
|
59
|
+
height_value = height_value.htb.reverse
|
60
|
+
Tapyrus.pack_var_int(height_value.bytesize) + height_value + header.to_payload
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'leveldb-native'
|
2
|
+
|
3
|
+
module Tapyrus
|
4
|
+
module Store
|
5
|
+
module DB
|
6
|
+
|
7
|
+
class LevelDB
|
8
|
+
|
9
|
+
attr_reader :db
|
10
|
+
attr_reader :logger
|
11
|
+
|
12
|
+
def initialize(path = "#{Tapyrus.base_dir}/db/spv")
|
13
|
+
# @logger = Tapyrus::Logger.create(:debug)
|
14
|
+
FileUtils.mkdir_p(path)
|
15
|
+
@db = ::LevelDBNative::DB.new(path)
|
16
|
+
# logger.debug 'Opened LevelDB successfully.'
|
17
|
+
end
|
18
|
+
|
19
|
+
# put data into LevelDB.
|
20
|
+
# @param [Object] key a key.
|
21
|
+
# @param [Object] value a value.
|
22
|
+
def put(key, value)
|
23
|
+
# logger.debug "put #{key} data"
|
24
|
+
db.put(key, value)
|
25
|
+
end
|
26
|
+
|
27
|
+
# get value from specified key.
|
28
|
+
# @param [Object] key a key.
|
29
|
+
# @return[Object] the stored value.
|
30
|
+
def get(key)
|
31
|
+
db.get(key)
|
32
|
+
end
|
33
|
+
|
34
|
+
# get best block hash.
|
35
|
+
def best_hash
|
36
|
+
db.get(KEY_PREFIX[:best])
|
37
|
+
end
|
38
|
+
|
39
|
+
# delete specified key data.
|
40
|
+
def delete(key)
|
41
|
+
db.delete(key)
|
42
|
+
end
|
43
|
+
|
44
|
+
# get block hash specified +height+
|
45
|
+
def get_hash_from_height(height)
|
46
|
+
db.get(height_key(height))
|
47
|
+
end
|
48
|
+
|
49
|
+
# get next block hash specified +hash+
|
50
|
+
def next_hash(hash)
|
51
|
+
db.get(KEY_PREFIX[:next] + hash)
|
52
|
+
end
|
53
|
+
|
54
|
+
# get entry payload
|
55
|
+
# @param [String] hash the hash with hex format.
|
56
|
+
# @return [String] the ChainEntry payload.
|
57
|
+
def get_entry_payload_from_hash(hash)
|
58
|
+
db.get(KEY_PREFIX[:entry] + hash)
|
59
|
+
end
|
60
|
+
|
61
|
+
def save_entry(entry)
|
62
|
+
db.batch do
|
63
|
+
db.put(entry.key ,entry.to_payload)
|
64
|
+
db.put(height_key(entry.height), entry.block_hash)
|
65
|
+
connect_entry(entry)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def close
|
70
|
+
db.close
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
# generate height key
|
76
|
+
def height_key(height)
|
77
|
+
height = height.to_even_length_hex
|
78
|
+
KEY_PREFIX[:height] + height.rhex
|
79
|
+
end
|
80
|
+
|
81
|
+
def connect_entry(entry)
|
82
|
+
unless entry.genesis?
|
83
|
+
tip_block = Tapyrus::Store::ChainEntry.parse_from_payload(get_entry_payload_from_hash(best_hash))
|
84
|
+
unless tip_block.block_hash == entry.prev_hash
|
85
|
+
raise "entry(#{entry.block_hash}) does not reference current best block hash(#{tip_block.block_hash})"
|
86
|
+
end
|
87
|
+
unless tip_block.height + 1 == entry.height
|
88
|
+
raise "block height is small than current best block."
|
89
|
+
end
|
90
|
+
end
|
91
|
+
db.put(KEY_PREFIX[:best], entry.block_hash)
|
92
|
+
db.put(KEY_PREFIX[:next] + entry.prev_hash, entry.block_hash)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
module Tapyrus
|
2
|
+
|
3
|
+
module Store
|
4
|
+
|
5
|
+
KEY_PREFIX = {
|
6
|
+
entry: 'e', # key: block hash, value: Tapyrus::Store::ChainEntry payload
|
7
|
+
height: 'h', # key: block height, value: block hash.
|
8
|
+
best: 'B', # value: best block hash.
|
9
|
+
next: 'n' # key: block hash, value: A hash of the next block of the specified hash
|
10
|
+
}
|
11
|
+
|
12
|
+
class SPVChain
|
13
|
+
|
14
|
+
attr_reader :db
|
15
|
+
attr_reader :logger
|
16
|
+
|
17
|
+
def initialize(db = Tapyrus::Store::DB::LevelDB.new)
|
18
|
+
@db = db # TODO multiple db switch
|
19
|
+
@logger = Tapyrus::Logger.create(:debug)
|
20
|
+
initialize_block
|
21
|
+
end
|
22
|
+
|
23
|
+
# get latest block in the store.
|
24
|
+
# @return[Tapyrus::Store::ChainEntry]
|
25
|
+
def latest_block
|
26
|
+
hash = db.best_hash
|
27
|
+
return nil unless hash
|
28
|
+
find_entry_by_hash(hash)
|
29
|
+
end
|
30
|
+
|
31
|
+
# find block entry with the specified height.
|
32
|
+
def find_entry_by_height(height)
|
33
|
+
find_entry_by_hash(db.get_hash_from_height(height))
|
34
|
+
end
|
35
|
+
|
36
|
+
# find block entry with the specified hash
|
37
|
+
def find_entry_by_hash(hash)
|
38
|
+
payload = db.get_entry_payload_from_hash(hash)
|
39
|
+
return nil unless payload
|
40
|
+
ChainEntry.parse_from_payload(payload)
|
41
|
+
end
|
42
|
+
|
43
|
+
# append block header to chain.
|
44
|
+
# @param [Tapyrus::BlockHeader] header a block header.
|
45
|
+
# @return [Tapyrus::Store::ChainEntry] appended block header entry.
|
46
|
+
def append_header(header)
|
47
|
+
logger.info("append header #{header.block_id}")
|
48
|
+
raise "this header is invalid. #{header.block_hash}" unless header.valid?
|
49
|
+
best_block = latest_block
|
50
|
+
current_height = best_block.height
|
51
|
+
if best_block.block_hash == header.prev_hash
|
52
|
+
entry = Tapyrus::Store::ChainEntry.new(header, current_height + 1)
|
53
|
+
db.save_entry(entry)
|
54
|
+
entry
|
55
|
+
else
|
56
|
+
unless find_entry_by_hash(header.block_hash)
|
57
|
+
# TODO implements recovery process
|
58
|
+
raise "header's previous hash(#{header.prev_hash}) does not match current best block's(#{best_block.block_hash})."
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# get next block hash for specified +hash+
|
64
|
+
# @param [String] hash the block hash(little endian)
|
65
|
+
# @return [String] the next block hash. If it does not exist yet, return nil.
|
66
|
+
def next_hash(hash)
|
67
|
+
db.next_hash(hash)
|
68
|
+
end
|
69
|
+
|
70
|
+
# get median time past for specified block +hash+
|
71
|
+
# @param [String] hash the block hash.
|
72
|
+
# @return [Integer] the median time past value.
|
73
|
+
def mtp(hash)
|
74
|
+
time = []
|
75
|
+
Tapyrus::MEDIAN_TIME_SPAN.times do
|
76
|
+
entry = find_entry_by_hash(hash)
|
77
|
+
break unless entry
|
78
|
+
|
79
|
+
time << entry.header.time
|
80
|
+
hash = entry.header.prev_hash
|
81
|
+
end
|
82
|
+
time.sort!
|
83
|
+
time[time.size / 2]
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
# if database is empty, put genesis block.
|
89
|
+
def initialize_block
|
90
|
+
unless latest_block
|
91
|
+
block = Tapyrus.chain_params.genesis_block
|
92
|
+
genesis = ChainEntry.new(block.header, 0)
|
93
|
+
db.save_entry(genesis)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|