Class: Bitcoin::Wallet::UtxoDB

Inherits:
Object
  • Object
show all
Includes:
AssetFeature
Defined in:
lib/bitcoin/wallet/utxo_db.rb

Constant Summary collapse

KEY_PREFIX =
{
  out_point: 'o',        # key: out_point(tx_hash and index), value: Utxo
  script: 's',           # key: script_pubkey and out_point(tx_hash and index), value: Utxo
  height: 'h',           # key: block_height and out_point, value: Utxo
  tx_hash: 't',          # key: tx_hash of transaction, value: [block_height, tx_index]
  block: 'b',            # key: block_height and tx_index, value: tx_hash
  tx_payload: 'p',            # key: tx_hash, value: Tx
}

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from AssetFeature

#delete_token, #get_asset_balance, #list_uncolored_unspent_in_account, #list_unspent_assets, #list_unspent_assets_in_account, #save_token

Constructor Details

#initialize(path = "#{Bitcoin.base_dir}/db/utxo") ⇒ UtxoDB

Returns a new instance of UtxoDB.



17
18
19
20
21
# File 'lib/bitcoin/wallet/utxo_db.rb', line 17

def initialize(path = "#{Bitcoin.base_dir}/db/utxo")
  FileUtils.mkdir_p(path)
  @level_db = ::LevelDB::DB.new(path)
  @logger = Bitcoin::Logger.create(:debug)
end

Instance Attribute Details

#level_dbObject (readonly)

Returns the value of attribute level_db.



15
16
17
# File 'lib/bitcoin/wallet/utxo_db.rb', line 15

def level_db
  @level_db
end

#loggerObject (readonly)

Returns the value of attribute logger.



15
16
17
# File 'lib/bitcoin/wallet/utxo_db.rb', line 15

def logger
  @logger
end

Instance Method Details

#closeObject



23
24
25
# File 'lib/bitcoin/wallet/utxo_db.rb', line 23

def close
  level_db.close
end

#delete_utxo(out_point) ⇒ Object



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/bitcoin/wallet/utxo_db.rb', line 82

def delete_utxo(out_point)
  level_db.batch do
    key = KEY_PREFIX[:out_point] + out_point.to_payload.bth
    return unless level_db.contains?(key)
    utxo = Bitcoin::Grpc::Utxo.decode(level_db.get(key).htb)
    level_db.delete(key)

    if utxo.script_pubkey
      key = KEY_PREFIX[:script] + utxo.script_pubkey + out_point.to_payload.bth
      level_db.delete(key)
    end

    key = KEY_PREFIX[:height] + [utxo.block_height].pack('N').bth + out_point.to_payload.bth
    level_db.delete(key)
    return utxo
  end
end

#get_balance(account, current_block_height: 9999999, min: 0, max: 9999999) ⇒ Object



122
123
124
# File 'lib/bitcoin/wallet/utxo_db.rb', line 122

def get_balance(, current_block_height: 9999999, min: 0, max: 9999999)
  (, current_block_height: current_block_height, min: min, max: max).sum { |u| u.value }
end

#get_tx(tx_hash) ⇒ block_height, ...

Returns:

  • (block_height, tx_index, tx_payload)


49
50
51
52
53
54
55
56
# File 'lib/bitcoin/wallet/utxo_db.rb', line 49

def get_tx(tx_hash)
  key = KEY_PREFIX[:tx_hash] + tx_hash
  return [] unless level_db.contains?(key)
  block_height, tx_index = level_db.get(key).htb.unpack('N2')
  key = KEY_PREFIX[:tx_payload] + tx_hash
  tx_payload = level_db.get(key)
  [block_height, tx_index, tx_payload]
end

#get_utxo(out_point) ⇒ Object



100
101
102
103
104
105
106
# File 'lib/bitcoin/wallet/utxo_db.rb', line 100

def get_utxo(out_point)
  level_db.batch do
    key = KEY_PREFIX[:out_point] + out_point.to_payload.bth
    return unless level_db.contains?(key)
    return Bitcoin::Grpc::Utxo.decode(level_db.get(key).htb)
  end
end

#list_unspent(current_block_height: 9999999, min: 0, max: 9999999, addresses: nil) ⇒ Object



108
109
110
111
112
113
114
# File 'lib/bitcoin/wallet/utxo_db.rb', line 108

def list_unspent(current_block_height: 9999999, min: 0, max: 9999999, addresses: nil)
  if addresses
    list_unspent_by_addresses(current_block_height, min: min, max: max, addresses: addresses)
  else
    list_unspent_by_block_height(current_block_height, min: min, max: max)
  end
end

#list_unspent_in_account(account, current_block_height: 9999999, min: 0, max: 9999999) ⇒ Object



116
117
118
119
120
# File 'lib/bitcoin/wallet/utxo_db.rb', line 116

def (, current_block_height: 9999999, min: 0, max: 9999999)
  return [] unless 
  script_pubkeys = .watch_targets.map { |t| Bitcoin::Script.to_p2wpkh(t).to_payload.bth }
  list_unspent_by_script_pubkeys(current_block_height, min: min, max: max, script_pubkeys: script_pubkeys)
end

#save_tx(tx_hash, tx_payload) ⇒ Object



27
28
29
30
31
32
33
# File 'lib/bitcoin/wallet/utxo_db.rb', line 27

def save_tx(tx_hash, tx_payload)
  level_db.batch do
    # tx_hash -> [block_height, tx_index]
    key = KEY_PREFIX[:tx_payload] + tx_hash
    level_db.put(key, tx_payload)
  end
end

#save_tx_position(tx_hash, block_height, tx_index) ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/bitcoin/wallet/utxo_db.rb', line 35

def save_tx_position(tx_hash, block_height, tx_index)
  logger.info("UtxoDB#save_tx:#{[tx_hash, block_height, tx_index]}")
  level_db.batch do
    # tx_hash -> [block_height, tx_index]
    key = KEY_PREFIX[:tx_hash] + tx_hash
    level_db.put(key, [block_height, tx_index].pack('N2').bth)

    # block_hash and tx_index -> tx_hash
    key = KEY_PREFIX[:block] + [block_height, tx_index].pack('N2').bth
    level_db.put(key, tx_hash)
  end
end

#save_utxo(out_point, value, script_pubkey, block_height) ⇒ Object



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/bitcoin/wallet/utxo_db.rb', line 58

def save_utxo(out_point, value, script_pubkey, block_height)
  logger.info("UtxoDB#save_utxo:#{[out_point, value, script_pubkey, block_height]}")
  level_db.batch do
    utxo = Bitcoin::Grpc::Utxo.new(tx_hash: out_point.txid.rhex, index: out_point.index, block_height: block_height, value: value, script_pubkey: script_pubkey)
    payload = utxo.to_proto.bth

    # out_point
    key = KEY_PREFIX[:out_point] + out_point.to_payload.bth
    return if level_db.contains?(key)
    level_db.put(key, payload)

    # script_pubkey
    if script_pubkey
      key = KEY_PREFIX[:script] + script_pubkey + out_point.to_payload.bth
      level_db.put(key, payload)
    end

    # block_height
    key = KEY_PREFIX[:height] + [block_height].pack('N').bth + out_point.to_payload.bth
    level_db.put(key, payload)
    return utxo
  end
end