bitcoinrb 1.12.0 → 1.12.1
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/.github/workflows/ruby.yml +1 -1
- data/bitcoinrb.gemspec +1 -6
- data/lib/bitcoin/bip324/fs_chacha20.rb +3 -5
- data/lib/bitcoin/bip324/fs_chacha_poly1305.rb +19 -17
- data/lib/bitcoin/bip324.rb +1 -1
- data/lib/bitcoin/descriptor/expression.rb +2 -2
- data/lib/bitcoin/descriptor/sp.rb +219 -0
- data/lib/bitcoin/descriptor.rb +20 -0
- data/lib/bitcoin/ext_key.rb +3 -3
- data/lib/bitcoin/message/ping.rb +4 -2
- data/lib/bitcoin/message/version.rb +1 -1
- data/lib/bitcoin/message_sign.rb +98 -38
- data/lib/bitcoin/rpc.rb +0 -2
- data/lib/bitcoin/silent_payment/output.rb +46 -0
- data/lib/bitcoin/silent_payment.rb +113 -12
- data/lib/bitcoin/util.rb +2 -2
- data/lib/bitcoin/version.rb +1 -1
- data/lib/bitcoin.rb +0 -6
- metadata +18 -108
- data/exe/bitcoinrb-cli +0 -5
- data/exe/bitcoinrbd +0 -46
- data/lib/bitcoin/network/connection.rb +0 -73
- data/lib/bitcoin/network/message_handler.rb +0 -243
- data/lib/bitcoin/network/peer.rb +0 -228
- data/lib/bitcoin/network/peer_discovery.rb +0 -42
- data/lib/bitcoin/network/pool.rb +0 -135
- data/lib/bitcoin/network.rb +0 -13
- data/lib/bitcoin/node/cli.rb +0 -122
- data/lib/bitcoin/node/configuration.rb +0 -40
- data/lib/bitcoin/node/spv.rb +0 -87
- data/lib/bitcoin/node.rb +0 -7
- data/lib/bitcoin/rpc/http_server.rb +0 -84
- data/lib/bitcoin/rpc/request_handler.rb +0 -150
- data/lib/bitcoin/store/chain_entry.rb +0 -68
- data/lib/bitcoin/store/db/level_db.rb +0 -98
- data/lib/bitcoin/store/db.rb +0 -9
- data/lib/bitcoin/store/spv_chain.rb +0 -101
- data/lib/bitcoin/store/utxo_db.rb +0 -226
- data/lib/bitcoin/store.rb +0 -12
data/lib/bitcoin/node/cli.rb
DELETED
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
require 'net/http'
|
|
2
|
-
require 'thor'
|
|
3
|
-
require 'json'
|
|
4
|
-
|
|
5
|
-
module Bitcoin
|
|
6
|
-
module Node
|
|
7
|
-
|
|
8
|
-
class CLI < Thor
|
|
9
|
-
|
|
10
|
-
class_option :network, aliases: '-n', default: :mainnet
|
|
11
|
-
|
|
12
|
-
desc 'decodepsbt <base64 psbt string>', "Return a JSON object representing the serialized, base64-encoded partially signed Bitcoin transaction."
|
|
13
|
-
def decodepsbt(base64)
|
|
14
|
-
psbt = Bitcoin::PSBT::Tx.parse_from_base64(base64)
|
|
15
|
-
puts JSON.pretty_generate(psbt.to_h)
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
desc 'getblockchaininfo', 'Returns an object containing various state info regarding blockchain processing.'
|
|
19
|
-
def getblockchaininfo
|
|
20
|
-
request('getblockchaininfo')
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
desc 'stop', 'Stop Bitcoin server.'
|
|
24
|
-
def stop
|
|
25
|
-
request('stop')
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
desc 'getblockheader "hash" ( verbose )', 'If verbose is false, returns a string that is serialized, hex-encoded data for blockheader "hash". If verbose is true, returns an Object with information about blockheader <hash>.'
|
|
29
|
-
def getblockheader(hash, verbose = true)
|
|
30
|
-
verbose = verbose.is_a?(String) ? (verbose == 'true') : verbose
|
|
31
|
-
request('getblockheader', hash, verbose)
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
desc 'getpeerinfo', 'Returns data about each connected network node as a json array of objects.'
|
|
35
|
-
def getpeerinfo
|
|
36
|
-
request('getpeerinfo')
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
desc 'decoderawtransaction "hexstring"', 'Return a JSON object representing the serialized, hex-encoded transaction.'
|
|
40
|
-
def decoderawtransaction(hexstring)
|
|
41
|
-
request('decoderawtransaction', hexstring)
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
desc 'decodescript "hexstring"', 'Decode a hex-encoded script.'
|
|
45
|
-
def decodescript(hexstring)
|
|
46
|
-
request('decodescript', hexstring)
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
# wallet cli
|
|
50
|
-
|
|
51
|
-
desc 'sendrawtransaction', 'Submits raw transaction (serialized, hex-encoded) to local node and network.'
|
|
52
|
-
def sendrawtransaction(hex_tx)
|
|
53
|
-
request('sendrawtransaction', hex_tx)
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
desc 'createwallet "wallet_id"', 'Create new HD wallet. It returns an error if an existing wallet_id is specified. '
|
|
57
|
-
def createwallet(wallet_id)
|
|
58
|
-
request('createwallet', wallet_id)
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
desc 'listwallets', 'Returns a list of currently loaded wallets. For full information on the wallet, use "getwalletinfo"'
|
|
62
|
-
def listwallets
|
|
63
|
-
request('listwallets')
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
desc 'getwalletinfo', 'Returns an object containing various wallet state info.'
|
|
67
|
-
def getwalletinfo
|
|
68
|
-
request('getwalletinfo')
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
desc 'listaccounts', '[WIP]Returns Object that has account names as keys, account balances as values.'
|
|
72
|
-
def listaccounts
|
|
73
|
-
request('listaccounts')
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
desc 'encryptwallet "passphrase"', 'Encrypts the wallet with "passphrase". This is for first time encryption.After this, any calls that interact with private keys such as sending or signing will require the passphrase to be set prior the making these calls.'
|
|
77
|
-
def encryptwallet(passhphrase)
|
|
78
|
-
request('encryptwallet', passhphrase)
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
desc 'getnewaddress "account"', 'Returns a new Bitcoin address for receiving payments.'
|
|
82
|
-
def getnewaddress(account)
|
|
83
|
-
request('getnewaddress', account)
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
private
|
|
87
|
-
|
|
88
|
-
def config
|
|
89
|
-
opts = {}
|
|
90
|
-
opts[:network] = options['network'] if options['network']
|
|
91
|
-
@conf ||= Bitcoin::Node::Configuration.new(opts)
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
def request(command, *params)
|
|
95
|
-
data = {
|
|
96
|
-
:method => command,
|
|
97
|
-
:params => params,
|
|
98
|
-
:id => 'jsonrpc'
|
|
99
|
-
}
|
|
100
|
-
begin
|
|
101
|
-
uri = URI.parse(config.server_url)
|
|
102
|
-
http = Net::HTTP.new(uri.hostname, uri.port)
|
|
103
|
-
http.use_ssl = uri.scheme === "https"
|
|
104
|
-
request = Net::HTTP::Post.new('/')
|
|
105
|
-
request.content_type = 'application/json'
|
|
106
|
-
request.body = data.to_json
|
|
107
|
-
response = http.request(request)
|
|
108
|
-
body = response.body
|
|
109
|
-
begin
|
|
110
|
-
json = JSON.parse(body.to_str)
|
|
111
|
-
puts JSON.pretty_generate(json)
|
|
112
|
-
rescue Exception
|
|
113
|
-
puts body.to_str
|
|
114
|
-
end
|
|
115
|
-
rescue Exception => e
|
|
116
|
-
puts e.message
|
|
117
|
-
end
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
end
|
|
121
|
-
end
|
|
122
|
-
end
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
require 'iniparse'
|
|
2
|
-
|
|
3
|
-
module Bitcoin
|
|
4
|
-
module Node
|
|
5
|
-
class Configuration
|
|
6
|
-
|
|
7
|
-
attr_reader :conf # Hash
|
|
8
|
-
|
|
9
|
-
# initialize configuration
|
|
10
|
-
# @param [Hash] opts parameter for node.
|
|
11
|
-
def initialize(opts = {})
|
|
12
|
-
# TODO apply configuration file.
|
|
13
|
-
opts[:network] = :mainnet unless opts[:network]
|
|
14
|
-
opts[:relay] = false unless opts[:relay]
|
|
15
|
-
Bitcoin.chain_params = opts[:network]
|
|
16
|
-
|
|
17
|
-
begin
|
|
18
|
-
ini_file = IniParse.parse(File.read("#{Bitcoin.base_dir}/bitcoinrb.conf"))
|
|
19
|
-
@conf = Hash[ ini_file.to_h['__anonymous__'].map{|k,v| [k.to_sym, v] } ]
|
|
20
|
-
rescue => e
|
|
21
|
-
@conf = {}
|
|
22
|
-
end
|
|
23
|
-
@conf.merge!(opts)
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def host
|
|
27
|
-
'localhost'
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def port
|
|
31
|
-
Bitcoin.chain_params.default_port - 1
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def server_url
|
|
35
|
-
"http://#{host}:#{port}"
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
end
|
data/lib/bitcoin/node/spv.rb
DELETED
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
module Bitcoin
|
|
2
|
-
module Node
|
|
3
|
-
|
|
4
|
-
# SPV class
|
|
5
|
-
class SPV
|
|
6
|
-
|
|
7
|
-
attr_reader :chain
|
|
8
|
-
attr_reader :pool
|
|
9
|
-
attr_reader :logger
|
|
10
|
-
attr_accessor :running
|
|
11
|
-
attr_reader :configuration
|
|
12
|
-
attr_accessor :server
|
|
13
|
-
attr_accessor :wallet
|
|
14
|
-
attr_accessor :bloom
|
|
15
|
-
|
|
16
|
-
# Initialize spv settings
|
|
17
|
-
# @param [Bitcoin::Node::Configuration] configuration configuration for spv.
|
|
18
|
-
#
|
|
19
|
-
# ```ruby
|
|
20
|
-
# config = Bitcoin::Node::Configuration.new(network: :mainnet)
|
|
21
|
-
# spv = Bitcoin::Node::SPV.new(config)
|
|
22
|
-
# spv.run
|
|
23
|
-
# ````
|
|
24
|
-
def initialize(configuration)
|
|
25
|
-
@chain = Bitcoin::Store::SPVChain.new
|
|
26
|
-
@configuration = configuration
|
|
27
|
-
@pool = Bitcoin::Network::Pool.new(self, @chain, @configuration)
|
|
28
|
-
@logger = Bitcoin::Logger.create(:debug)
|
|
29
|
-
@running = false
|
|
30
|
-
@wallet = Bitcoin::Wallet::Base.current_wallet
|
|
31
|
-
# TODO : optimize bloom filter parameters
|
|
32
|
-
setup_filter
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
# open the node.
|
|
36
|
-
def run
|
|
37
|
-
# TODO need process running check.
|
|
38
|
-
return if running
|
|
39
|
-
logger.debug 'SPV node start running.'
|
|
40
|
-
EM.run do
|
|
41
|
-
# EM.start_server('0.0.0.0', Bitcoin.chain_params.default_port, Bitcoin::Network::InboundConnector, self)
|
|
42
|
-
pool.start
|
|
43
|
-
@server = Bitcoin::RPC::HttpServer.run(self, configuration.port)
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
# close the node.
|
|
48
|
-
def shutdown
|
|
49
|
-
pool.terminate
|
|
50
|
-
logger.debug 'SPV node shutdown.'
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
# broadcast a transaction
|
|
54
|
-
def broadcast(tx)
|
|
55
|
-
pool.broadcast(tx)
|
|
56
|
-
logger.debug "broadcast tx: #{tx.to_hex}"
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
# add filter element to bloom filter.
|
|
60
|
-
# [String] element. the hex string of txid, public key, public key hash or outpoint.
|
|
61
|
-
def filter_add(element)
|
|
62
|
-
bloom.add(element)
|
|
63
|
-
pool.filter_add(element)
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
# clear bloom filter.
|
|
67
|
-
def filter_clear
|
|
68
|
-
pool.filter_clear
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
def add_observer(observer)
|
|
72
|
-
pool.add_observer(observer)
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def delete_observer(observer)
|
|
76
|
-
pool.delete_observer(observer)
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
private
|
|
80
|
-
|
|
81
|
-
def setup_filter
|
|
82
|
-
@bloom = Bitcoin::BloomFilter.create_filter(512, 0.01)
|
|
83
|
-
wallet.watch_targets.each{|t|bloom.add(t.htb)} if wallet
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
end
|
data/lib/bitcoin/node.rb
DELETED
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
require 'evma_httpserver'
|
|
2
|
-
require 'json'
|
|
3
|
-
|
|
4
|
-
module Bitcoin
|
|
5
|
-
module RPC
|
|
6
|
-
|
|
7
|
-
# Bitcoinrb RPC server.
|
|
8
|
-
class HttpServer < EM::Connection
|
|
9
|
-
include EM::HttpServer
|
|
10
|
-
include RequestHandler
|
|
11
|
-
|
|
12
|
-
SUPPORTED_COMMANDS = %w[
|
|
13
|
-
getblockchaininfo
|
|
14
|
-
stop
|
|
15
|
-
getblockheader
|
|
16
|
-
getpeerinfo
|
|
17
|
-
sendrawtransaction
|
|
18
|
-
decoderawtransaction
|
|
19
|
-
decodescript
|
|
20
|
-
createwallet
|
|
21
|
-
listwallets
|
|
22
|
-
getwalletinfo
|
|
23
|
-
listaccounts
|
|
24
|
-
encryptwallet
|
|
25
|
-
getnewaddress
|
|
26
|
-
].freeze
|
|
27
|
-
|
|
28
|
-
attr_reader :node
|
|
29
|
-
attr_accessor :logger
|
|
30
|
-
|
|
31
|
-
def initialize(node)
|
|
32
|
-
@node = node
|
|
33
|
-
@logger = Bitcoin::Logger.create(:debug)
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def post_init
|
|
37
|
-
super
|
|
38
|
-
logger.debug 'start http server.'
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def self.run(node, port = 8332)
|
|
42
|
-
EM.start_server('0.0.0.0', port, HttpServer, node)
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
# process http request.
|
|
46
|
-
def process_http_request
|
|
47
|
-
operation = proc {
|
|
48
|
-
command, args = parse_json_params
|
|
49
|
-
logger.debug("process http request. command = #{command}")
|
|
50
|
-
unless SUPPORTED_COMMANDS.include?(command)
|
|
51
|
-
raise ArgumentError, "Unsupported method: #{command}"
|
|
52
|
-
end
|
|
53
|
-
begin
|
|
54
|
-
send(command, *args).to_json
|
|
55
|
-
rescue Exception => e
|
|
56
|
-
e
|
|
57
|
-
end
|
|
58
|
-
}
|
|
59
|
-
callback = proc{ |result|
|
|
60
|
-
response = EM::DelegatedHttpResponse.new(self)
|
|
61
|
-
if result.is_a?(Exception)
|
|
62
|
-
response.status = 500
|
|
63
|
-
response.content = result.message
|
|
64
|
-
else
|
|
65
|
-
response.status = 200
|
|
66
|
-
response.content = result
|
|
67
|
-
end
|
|
68
|
-
response.content_type 'application/json'
|
|
69
|
-
response.send_response
|
|
70
|
-
}
|
|
71
|
-
EM.defer(operation, callback)
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
# parse request parameter.
|
|
75
|
-
# @return [Array] the array of command and args
|
|
76
|
-
def parse_json_params
|
|
77
|
-
params = JSON.parse(@http_post_content)
|
|
78
|
-
[params['method'], params['params']]
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
end
|
|
84
|
-
end
|
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
module Bitcoin
|
|
2
|
-
module RPC
|
|
3
|
-
|
|
4
|
-
# RPC server's request handler.
|
|
5
|
-
module RequestHandler
|
|
6
|
-
|
|
7
|
-
# Returns an object containing various state info regarding blockchain processing.
|
|
8
|
-
def getblockchaininfo
|
|
9
|
-
h = {}
|
|
10
|
-
h[:chain] = Bitcoin.chain_params.network
|
|
11
|
-
best_block = node.chain.latest_block
|
|
12
|
-
h[:headers] = best_block.height
|
|
13
|
-
h[:bestblockhash] = best_block.header.block_id
|
|
14
|
-
h[:chainwork] = best_block.header.work
|
|
15
|
-
h[:mediantime] = node.chain.mtp(best_block.block_hash)
|
|
16
|
-
h
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
# shutdown node
|
|
20
|
-
def stop
|
|
21
|
-
node.shutdown
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
# get block header information.
|
|
25
|
-
# @param [String] block_id block hash(big endian)
|
|
26
|
-
def getblockheader(block_id, verbose)
|
|
27
|
-
block_hash = block_id.rhex
|
|
28
|
-
entry = node.chain.find_entry_by_hash(block_hash)
|
|
29
|
-
raise ArgumentError.new('Block not found') unless entry
|
|
30
|
-
if verbose
|
|
31
|
-
{
|
|
32
|
-
hash: block_id,
|
|
33
|
-
height: entry.height,
|
|
34
|
-
version: entry.header.version,
|
|
35
|
-
versionHex: entry.header.version.to_even_length_hex,
|
|
36
|
-
merkleroot: entry.header.merkle_root.rhex,
|
|
37
|
-
time: entry.header.time,
|
|
38
|
-
mediantime: node.chain.mtp(block_hash),
|
|
39
|
-
nonce: entry.header.nonce,
|
|
40
|
-
bits: entry.header.bits.to_even_length_hex,
|
|
41
|
-
previousblockhash: entry.prev_hash.rhex,
|
|
42
|
-
nextblockhash: node.chain.next_hash(block_hash).rhex
|
|
43
|
-
}
|
|
44
|
-
else
|
|
45
|
-
entry.header.to_hex
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
# Returns connected peer information.
|
|
50
|
-
def getpeerinfo
|
|
51
|
-
node.pool.peers.map do |peer|
|
|
52
|
-
local_addr = "#{peer.remote_version.remote_addr.addr_string}:18333"
|
|
53
|
-
{
|
|
54
|
-
id: peer.id,
|
|
55
|
-
addr: "#{peer.host}:#{peer.port}",
|
|
56
|
-
addrlocal: local_addr,
|
|
57
|
-
services: peer.remote_version.services.to_even_length_hex.rjust(16, '0'),
|
|
58
|
-
relaytxes: peer.remote_version.relay,
|
|
59
|
-
lastsend: peer.last_send,
|
|
60
|
-
lastrecv: peer.last_recv,
|
|
61
|
-
bytessent: peer.bytes_sent,
|
|
62
|
-
bytesrecv: peer.bytes_recv,
|
|
63
|
-
conntime: peer.conn_time,
|
|
64
|
-
pingtime: peer.ping_time,
|
|
65
|
-
minping: peer.min_ping,
|
|
66
|
-
version: peer.remote_version.version,
|
|
67
|
-
subver: peer.remote_version.user_agent,
|
|
68
|
-
inbound: !peer.outbound?,
|
|
69
|
-
startingheight: peer.remote_version.start_height,
|
|
70
|
-
best_hash: peer.best_hash,
|
|
71
|
-
best_height: peer.best_height
|
|
72
|
-
}
|
|
73
|
-
end
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
# broadcast transaction
|
|
77
|
-
def sendrawtransaction(hex_tx)
|
|
78
|
-
tx = Bitcoin::Tx.parse_from_payload(hex_tx.htb, strict: true)
|
|
79
|
-
# TODO check wether tx is valid
|
|
80
|
-
node.broadcast(tx)
|
|
81
|
-
tx.txid
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
# decode tx data.
|
|
85
|
-
def decoderawtransaction(hex_tx)
|
|
86
|
-
begin
|
|
87
|
-
Bitcoin::Tx.parse_from_payload(hex_tx.htb, strict: true ).to_h
|
|
88
|
-
rescue Exception
|
|
89
|
-
raise ArgumentError.new('TX decode failed')
|
|
90
|
-
end
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
# decode script data.
|
|
94
|
-
def decodescript(hex_script)
|
|
95
|
-
begin
|
|
96
|
-
script = Bitcoin::Script.parse_from_payload(hex_script.htb)
|
|
97
|
-
h = script.to_h
|
|
98
|
-
h.delete(:hex)
|
|
99
|
-
h[:p2sh] = script.to_p2sh.to_addr unless script.p2sh?
|
|
100
|
-
h
|
|
101
|
-
rescue Exception
|
|
102
|
-
raise ArgumentError.new('Script decode failed')
|
|
103
|
-
end
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
# wallet api
|
|
107
|
-
|
|
108
|
-
# create wallet
|
|
109
|
-
def createwallet(wallet_id = 1, wallet_path_prefix = Bitcoin::Wallet::Base.default_path_prefix)
|
|
110
|
-
wallet = Bitcoin::Wallet::Base.create(wallet_id, wallet_path_prefix)
|
|
111
|
-
node.wallet = wallet unless node.wallet
|
|
112
|
-
{wallet_id: wallet.wallet_id, mnemonic: wallet.master_key.mnemonic}
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
# get wallet list.
|
|
116
|
-
def listwallets(wallet_path_prefix = Bitcoin::Wallet::Base.default_path_prefix)
|
|
117
|
-
Bitcoin::Wallet::Base.wallet_paths(wallet_path_prefix)
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
# get current wallet information.
|
|
121
|
-
def getwalletinfo
|
|
122
|
-
node.wallet ? node.wallet.to_h : {}
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
# get the list of current Wallet accounts.
|
|
126
|
-
def listaccounts
|
|
127
|
-
return {} unless node.wallet
|
|
128
|
-
accounts = {}
|
|
129
|
-
node.wallet.accounts.each do |a|
|
|
130
|
-
accounts[a.name] = node.wallet.get_balance(a)
|
|
131
|
-
end
|
|
132
|
-
accounts
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
# encrypt wallet.
|
|
136
|
-
def encryptwallet(passphrase)
|
|
137
|
-
return nil unless node.wallet
|
|
138
|
-
node.wallet.encrypt(passphrase)
|
|
139
|
-
"The wallet 'wallet_id: #{node.wallet.wallet_id}' has been encrypted."
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
# create new bitcoin address for receiving payments.
|
|
143
|
-
def getnewaddress(account_name)
|
|
144
|
-
node.wallet.generate_new_address(account_name)
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
end
|
|
150
|
-
end
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
module Bitcoin
|
|
2
|
-
module Store
|
|
3
|
-
|
|
4
|
-
# wrap a block header object with extra data.
|
|
5
|
-
class ChainEntry
|
|
6
|
-
include Bitcoin::HexConverter
|
|
7
|
-
|
|
8
|
-
attr_reader :header
|
|
9
|
-
attr_reader :height
|
|
10
|
-
|
|
11
|
-
# @param [Bitcoin::BlockHeader] header a block header.
|
|
12
|
-
# @param [Integer] height a block height.
|
|
13
|
-
def initialize(header, height)
|
|
14
|
-
@header = header
|
|
15
|
-
@height = height
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
# get database key
|
|
19
|
-
def key
|
|
20
|
-
Bitcoin::Store::KEY_PREFIX[:entry] + header.block_hash
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def hash
|
|
24
|
-
header.hash
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
# block hash
|
|
28
|
-
def block_hash
|
|
29
|
-
header.block_hash
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
# previous block hash
|
|
33
|
-
def prev_hash
|
|
34
|
-
header.prev_hash
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
# whether genesis block
|
|
38
|
-
def genesis?
|
|
39
|
-
Bitcoin.chain_params.genesis_block.header == header
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
# @param [String] payload a payload with binary format.
|
|
43
|
-
def self.parse_from_payload(payload)
|
|
44
|
-
buf = StringIO.new(payload)
|
|
45
|
-
len = Bitcoin.unpack_var_int_from_io(buf)
|
|
46
|
-
height = buf.read(len).reverse.bth.to_i(16)
|
|
47
|
-
new(Bitcoin::BlockHeader.parse_from_payload(buf.read(80)), height)
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
# build next block +StoredBlock+ instance.
|
|
51
|
-
# @param [Bitcoin::BlockHeader] next_block a next block candidate header.
|
|
52
|
-
# @return [Bitcoin::Store::ChainEntry] a next stored block (not saved).
|
|
53
|
-
def build_next_block(next_block)
|
|
54
|
-
ChainEntry.new(next_block, height + 1)
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
# generate payload
|
|
58
|
-
def to_payload
|
|
59
|
-
height_value = height.to_even_length_hex
|
|
60
|
-
height_value = height_value.htb.reverse
|
|
61
|
-
Bitcoin.pack_var_int(height_value.bytesize) + height_value + header.to_payload
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
end
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
require 'leveldb-native'
|
|
2
|
-
|
|
3
|
-
module Bitcoin
|
|
4
|
-
module Store
|
|
5
|
-
module DB
|
|
6
|
-
|
|
7
|
-
class LevelDB
|
|
8
|
-
|
|
9
|
-
attr_reader :db
|
|
10
|
-
attr_reader :logger
|
|
11
|
-
|
|
12
|
-
def initialize(path = "#{Bitcoin.base_dir}/db/spv")
|
|
13
|
-
# @logger = Bitcoin::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 = Bitcoin::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
|