Class: Tapyrus::Store::SPVChain

Inherits:
Object
  • Object
show all
Defined in:
lib/tapyrus/store/spv_chain.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(db = Tapyrus::Store::DB::LevelDB.new, genesis: nil) ⇒ SPVChain

initialize spv chain @param db @param genesis genesis block

Raises:

  • (ArgumentError)


19
20
21
22
23
24
# File 'lib/tapyrus/store/spv_chain.rb', line 19

def initialize(db = Tapyrus::Store::DB::LevelDB.new, genesis: nil)
  raise ArgumentError, "genesis block should be specified." unless genesis
  @db = db # TODO multiple db switch
  @logger = Tapyrus::Logger.create(:debug)
  initialize_block(genesis)
end

Instance Attribute Details

#dbObject (readonly)

Returns the value of attribute db.



13
14
15
# File 'lib/tapyrus/store/spv_chain.rb', line 13

def db
  @db
end

#loggerObject (readonly)

Returns the value of attribute logger.



14
15
16
# File 'lib/tapyrus/store/spv_chain.rb', line 14

def logger
  @logger
end

Instance Method Details

#add_agg_pubkey(active_height, agg_pubkey) ⇒ Object

Add aggregated public key.

Parameters:

  • active_height (Integer)
  • agg_pubkey (String)

    aggregated public key with hex format.



94
95
96
# File 'lib/tapyrus/store/spv_chain.rb', line 94

def add_agg_pubkey(active_height, agg_pubkey)
  db.add_agg_pubkey(active_height, agg_pubkey)
end

#agg_pubkeysArray[Array(height, agg_pubkey)]

get aggregated public key keys.

Returns:

  • (Array[Array(height, agg_pubkey)])

    the list of public keys.



100
101
102
# File 'lib/tapyrus/store/spv_chain.rb', line 100

def agg_pubkeys
  db.agg_pubkeys
end

#append_header(header) ⇒ Tapyrus::Store::ChainEntry

append block header to chain.

Parameters:

Returns:



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/tapyrus/store/spv_chain.rb', line 49

def append_header(header)
  logger.info("append header #{header.block_id}")
  best_block = latest_block
  current_height = best_block.height
  unless header.valid?(db.agg_pubkey_with_height(current_height + 1))
    raise "this header is invalid. #{header.block_hash}"
  end
  if best_block.block_hash == header.prev_hash
    entry = Tapyrus::Store::ChainEntry.new(header, current_height + 1)
    db.save_entry(entry)
    entry
  else
    unless find_entry_by_hash(header.block_hash)
      # TODO implements recovery process
      raise "header's previous hash(#{header.prev_hash}) does not match current best block's(#{best_block.block_hash})."
    end
  end
end

#find_entry_by_hash(hash) ⇒ Object

find block entry with the specified hash



40
41
42
43
44
# File 'lib/tapyrus/store/spv_chain.rb', line 40

def find_entry_by_hash(hash)
  payload = db.get_entry_payload_from_hash(hash)
  return nil unless payload
  ChainEntry.parse_from_payload(payload)
end

#find_entry_by_height(height) ⇒ Object

find block entry with the specified height.



35
36
37
# File 'lib/tapyrus/store/spv_chain.rb', line 35

def find_entry_by_height(height)
  find_entry_by_hash(db.get_hash_from_height(height))
end

#latest_blockObject

get latest block in the store. @return



28
29
30
31
32
# File 'lib/tapyrus/store/spv_chain.rb', line 28

def latest_block
  hash = db.best_hash
  return nil unless hash
  find_entry_by_hash(hash)
end

#mtp(hash) ⇒ Integer

get median time past for specified block hash

Parameters:

  • hash (String)

    the block hash.

Returns:

  • (Integer)

    the median time past value.



78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/tapyrus/store/spv_chain.rb', line 78

def mtp(hash)
  time = []
  Tapyrus::MEDIAN_TIME_SPAN.times do
    entry = find_entry_by_hash(hash)
    break unless entry

    time << entry.header.time
    hash = entry.header.prev_hash
  end
  time.sort!
  time[time.size / 2]
end

#next_hash(hash) ⇒ String

get next block hash for specified hash

Parameters:

  • hash (String)

    the block hash(little endian)

Returns:

  • (String)

    the next block hash. If it does not exist yet, return nil.



71
72
73
# File 'lib/tapyrus/store/spv_chain.rb', line 71

def next_hash(hash)
  db.next_hash(hash)
end