bitcoinrb-grpc 0.1.0
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 +7 -0
- data/.gitignore +12 -0
- data/.rspec +3 -0
- data/.travis.yml +7 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +6 -0
- data/README.md +66 -0
- data/Rakefile +6 -0
- data/bin/bitcoinrbd +60 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/bitcoinrb-grpc.gemspec +36 -0
- data/lib/bitcoin/grpc.rb +35 -0
- data/lib/bitcoin/grpc/grpc_pb.rb +99 -0
- data/lib/bitcoin/grpc/grpc_services_pb.rb +26 -0
- data/lib/bitcoin/grpc/oap_service.rb +28 -0
- data/lib/bitcoin/grpc/server.rb +113 -0
- data/lib/bitcoin/grpc/version.rb +5 -0
- data/lib/bitcoin/wallet/asset_feature.rb +132 -0
- data/lib/bitcoin/wallet/asset_handler.rb +58 -0
- data/lib/bitcoin/wallet/publisher.rb +32 -0
- data/lib/bitcoin/wallet/signer.rb +71 -0
- data/lib/bitcoin/wallet/utxo_db.rb +163 -0
- data/lib/bitcoin/wallet/utxo_handler.rb +90 -0
- data/lib/extensions/bitcoin/rpc/request_handler.rb +99 -0
- data/lib/extensions/bitcoin/tx.rb +11 -0
- data/lib/extensions/bitcoin/wallet/base.rb +50 -0
- data/proto/bitcoin/grpc/grpc.proto +97 -0
- metadata +210 -0
@@ -0,0 +1,163 @@
|
|
1
|
+
module Bitcoin
|
2
|
+
module Wallet
|
3
|
+
class UtxoDB
|
4
|
+
include Bitcoin::Wallet::AssetFeature
|
5
|
+
|
6
|
+
KEY_PREFIX = {
|
7
|
+
out_point: 'o', # key: out_point(tx_hash and index), value: Utxo
|
8
|
+
script: 's', # key: script_pubkey and out_point(tx_hash and index), value: Utxo
|
9
|
+
height: 'h', # key: block_height and out_point, value: Utxo
|
10
|
+
tx_hash: 't', # key: tx_hash of transaction, value: [block_height, tx_index]
|
11
|
+
block: 'b', # key: block_height and tx_index, value: tx_hash
|
12
|
+
tx_payload: 'p', # key: tx_hash, value: Tx
|
13
|
+
}
|
14
|
+
|
15
|
+
attr_reader :level_db, :logger
|
16
|
+
|
17
|
+
def initialize(path = "#{Bitcoin.base_dir}/db/utxo")
|
18
|
+
FileUtils.mkdir_p(path)
|
19
|
+
@level_db = ::LevelDB::DB.new(path)
|
20
|
+
@logger = Bitcoin::Logger.create(:debug)
|
21
|
+
end
|
22
|
+
|
23
|
+
def close
|
24
|
+
level_db.close
|
25
|
+
end
|
26
|
+
|
27
|
+
def save_tx(tx_hash, tx_payload)
|
28
|
+
level_db.batch do
|
29
|
+
# tx_hash -> [block_height, tx_index]
|
30
|
+
key = KEY_PREFIX[:tx_payload] + tx_hash
|
31
|
+
level_db.put(key, tx_payload)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def save_tx_position(tx_hash, block_height, tx_index)
|
36
|
+
logger.info("UtxoDB#save_tx:#{[tx_hash, block_height, tx_index]}")
|
37
|
+
level_db.batch do
|
38
|
+
# tx_hash -> [block_height, tx_index]
|
39
|
+
key = KEY_PREFIX[:tx_hash] + tx_hash
|
40
|
+
level_db.put(key, [block_height, tx_index].pack('N2').bth)
|
41
|
+
|
42
|
+
# block_hash and tx_index -> tx_hash
|
43
|
+
key = KEY_PREFIX[:block] + [block_height, tx_index].pack('N2').bth
|
44
|
+
level_db.put(key, tx_hash)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# @return [block_height, tx_index, tx_payload]
|
49
|
+
def get_tx(tx_hash)
|
50
|
+
key = KEY_PREFIX[:tx_hash] + tx_hash
|
51
|
+
return [] unless level_db.contains?(key)
|
52
|
+
block_height, tx_index = level_db.get(key).htb.unpack('N2')
|
53
|
+
key = KEY_PREFIX[:tx_payload] + tx_hash
|
54
|
+
tx_payload = level_db.get(key)
|
55
|
+
[block_height, tx_index, tx_payload]
|
56
|
+
end
|
57
|
+
|
58
|
+
def save_utxo(out_point, value, script_pubkey, block_height)
|
59
|
+
logger.info("UtxoDB#save_utxo:#{[out_point, value, script_pubkey, block_height]}")
|
60
|
+
level_db.batch do
|
61
|
+
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)
|
62
|
+
payload = utxo.to_proto.bth
|
63
|
+
|
64
|
+
# out_point
|
65
|
+
key = KEY_PREFIX[:out_point] + out_point.to_payload.bth
|
66
|
+
return if level_db.contains?(key)
|
67
|
+
level_db.put(key, payload)
|
68
|
+
|
69
|
+
# script_pubkey
|
70
|
+
if script_pubkey
|
71
|
+
key = KEY_PREFIX[:script] + script_pubkey + out_point.to_payload.bth
|
72
|
+
level_db.put(key, payload)
|
73
|
+
end
|
74
|
+
|
75
|
+
# block_height
|
76
|
+
key = KEY_PREFIX[:height] + [block_height].pack('N').bth + out_point.to_payload.bth
|
77
|
+
level_db.put(key, payload)
|
78
|
+
return utxo
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def delete_utxo(out_point)
|
83
|
+
level_db.batch do
|
84
|
+
key = KEY_PREFIX[:out_point] + out_point.to_payload.bth
|
85
|
+
return unless level_db.contains?(key)
|
86
|
+
utxo = Bitcoin::Grpc::Utxo.decode(level_db.get(key).htb)
|
87
|
+
level_db.delete(key)
|
88
|
+
|
89
|
+
if utxo.script_pubkey
|
90
|
+
key = KEY_PREFIX[:script] + utxo.script_pubkey + out_point.to_payload.bth
|
91
|
+
level_db.delete(key)
|
92
|
+
end
|
93
|
+
|
94
|
+
key = KEY_PREFIX[:height] + [utxo.block_height].pack('N').bth + out_point.to_payload.bth
|
95
|
+
level_db.delete(key)
|
96
|
+
return utxo
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def get_utxo(out_point)
|
101
|
+
level_db.batch do
|
102
|
+
key = KEY_PREFIX[:out_point] + out_point.to_payload.bth
|
103
|
+
return unless level_db.contains?(key)
|
104
|
+
return Bitcoin::Grpc::Utxo.decode(level_db.get(key).htb)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def list_unspent(current_block_height: 9999999, min: 0, max: 9999999, addresses: nil)
|
109
|
+
if addresses
|
110
|
+
list_unspent_by_addresses(current_block_height, min: min, max: max, addresses: addresses)
|
111
|
+
else
|
112
|
+
list_unspent_by_block_height(current_block_height, min: min, max: max)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def list_unspent_in_account(account, current_block_height: 9999999, min: 0, max: 9999999)
|
117
|
+
return [] unless account
|
118
|
+
script_pubkeys = account.watch_targets.map { |t| Bitcoin::Script.to_p2wpkh(t).to_payload.bth }
|
119
|
+
list_unspent_by_script_pubkeys(current_block_height, min: min, max: max, script_pubkeys: script_pubkeys)
|
120
|
+
end
|
121
|
+
|
122
|
+
def get_balance(account, current_block_height: 9999999, min: 0, max: 9999999)
|
123
|
+
list_unspent_in_account(account, current_block_height: current_block_height, min: min, max: max).sum { |u| u.value }
|
124
|
+
end
|
125
|
+
|
126
|
+
private
|
127
|
+
|
128
|
+
def utxos_between(from, to)
|
129
|
+
level_db.each(from: from, to: to).map { |k, v| Bitcoin::Grpc::Utxo.decode(v.htb) }
|
130
|
+
end
|
131
|
+
|
132
|
+
class ::Array
|
133
|
+
def with_height(min, max)
|
134
|
+
select { |u| u.block_height >= min && u.block_height <= max }
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def list_unspent_by_block_height(current_block_height, min: 0, max: 9999999)
|
139
|
+
max_height = [current_block_height - min, 0].max
|
140
|
+
min_height = [current_block_height - max, 0].max
|
141
|
+
|
142
|
+
from = KEY_PREFIX[:height] + [min_height].pack('N').bth + '000000000000000000000000000000000000000000000000000000000000000000000000'
|
143
|
+
to = KEY_PREFIX[:height] + [max_height].pack('N').bth + 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
|
144
|
+
utxos_between(from, to)
|
145
|
+
end
|
146
|
+
|
147
|
+
def list_unspent_by_addresses(current_block_height, min: 0, max: 9999999, addresses: [])
|
148
|
+
script_pubkeys = addresses.map { |a| Bitcoin::Script.parse_from_addr(a).to_payload.bth }
|
149
|
+
list_unspent_by_script_pubkeys(current_block_height, min: min, max: max, script_pubkeys: script_pubkeys)
|
150
|
+
end
|
151
|
+
|
152
|
+
def list_unspent_by_script_pubkeys(current_block_height, min: 0, max: 9999999, script_pubkeys: [])
|
153
|
+
max_height = current_block_height - min
|
154
|
+
min_height = current_block_height - max
|
155
|
+
script_pubkeys.map do |key|
|
156
|
+
from = KEY_PREFIX[:script] + key + '000000000000000000000000000000000000000000000000000000000000000000000000'
|
157
|
+
to = KEY_PREFIX[:script] + key + 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
|
158
|
+
utxos_between(from, to).with_height(min_height, max_height)
|
159
|
+
end.flatten
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module Bitcoin
|
2
|
+
module Wallet
|
3
|
+
class UtxoHandler < Concurrent::Actor::Context
|
4
|
+
attr_reader :watchings, :spv, :utxo_db, :publisher
|
5
|
+
|
6
|
+
def initialize(spv, publisher)
|
7
|
+
@watchings = []
|
8
|
+
@spv = spv
|
9
|
+
@spv.add_observer(self)
|
10
|
+
|
11
|
+
@utxo_db = spv.wallet.utxo_db
|
12
|
+
@publisher = publisher
|
13
|
+
end
|
14
|
+
|
15
|
+
def update(event, data)
|
16
|
+
send(event, data)
|
17
|
+
end
|
18
|
+
|
19
|
+
def on_message(message)
|
20
|
+
case message
|
21
|
+
when Bitcoin::Grpc::WatchTxConfirmedRequest
|
22
|
+
spv.filter_add(message.tx_hash)
|
23
|
+
watchings << message
|
24
|
+
when :watchings
|
25
|
+
watchings
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def tx(data)
|
32
|
+
tx = data.tx
|
33
|
+
block_height = spv.chain.latest_block.height
|
34
|
+
watch_targets = spv.wallet.watch_targets
|
35
|
+
|
36
|
+
tx.outputs.each_with_index do |output, index|
|
37
|
+
next unless watch_targets.find { |target| output.script_pubkey == Bitcoin::Script.to_p2wpkh(target) }
|
38
|
+
out_point = Bitcoin::OutPoint.new(tx.tx_hash, index)
|
39
|
+
utxo = utxo_db.save_utxo(out_point, output.value, output.script_pubkey.to_payload.bth, block_height)
|
40
|
+
publisher << Bitcoin::Grpc::EventUtxoRegistered.new(tx_hash: tx.tx_hash, tx_payload: tx.to_payload.bth, utxo: utxo) if utxo
|
41
|
+
end
|
42
|
+
|
43
|
+
tx.inputs.each do |input|
|
44
|
+
utxo = utxo_db.delete_utxo(input.out_point)
|
45
|
+
publisher << Bitcoin::Grpc::EventUtxoSpent.new(tx_hash: tx.tx_hash, tx_payload: tx.to_payload.bth, utxo: utxo) if utxo
|
46
|
+
end
|
47
|
+
|
48
|
+
utxo_db.save_tx(tx.tx_hash, tx.to_payload.bth)
|
49
|
+
|
50
|
+
publisher << Bitcoin::Grpc::WatchAssetIdAssignedRequest.new(tx_hash: tx.tx_hash, tx_payload: tx.to_payload.bth) if tx.colored?
|
51
|
+
end
|
52
|
+
|
53
|
+
def merkleblock(data)
|
54
|
+
block_height = spv.chain.latest_block.height
|
55
|
+
tree = Bitcoin::MerkleTree.build_partial(data.tx_count, data.hashes, Bitcoin.byte_to_bit(data.flags.htb))
|
56
|
+
tx_blockhash = data.header.block_hash
|
57
|
+
|
58
|
+
log(::Logger::DEBUG, "UtxoHandler#merkleblock:#{data.hashes}")
|
59
|
+
|
60
|
+
watchings
|
61
|
+
.select { |item| item.is_a? Bitcoin::Grpc::WatchTxConfirmedRequest }
|
62
|
+
.select { |item| data.hashes.include?(item.tx_hash) }
|
63
|
+
.each do |item|
|
64
|
+
tx_index = tree.find_node(item.tx_hash).index
|
65
|
+
log(::Logger::DEBUG, "UtxoHandler#merkleblock:#{[tx_index]}")
|
66
|
+
next unless tx_index
|
67
|
+
utxo_db.save_tx_position(item.tx_hash, block_height, tx_index)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def header(data)
|
72
|
+
log(::Logger::DEBUG, "UtxoHandler#header:#{[data, watchings]}")
|
73
|
+
block_height = data[:height]
|
74
|
+
watchings.select do |item|
|
75
|
+
case item
|
76
|
+
when Bitcoin::Grpc::WatchTxConfirmedRequest
|
77
|
+
height, tx_index, tx_payload = utxo_db.get_tx(item.tx_hash)
|
78
|
+
log(::Logger::DEBUG, "UtxoHandler#header:#{[height, tx_index]}")
|
79
|
+
next unless (height || tx_index)
|
80
|
+
if block_height >= height + item.confirmations
|
81
|
+
publisher << Bitcoin::Grpc::EventTxConfirmed.new(tx_hash: item.tx_hash, tx_payload: tx_payload, block_height: height, tx_index: tx_index, confirmations: item.confirmations)
|
82
|
+
watchings.delete(item)
|
83
|
+
end
|
84
|
+
else
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
module Bitcoin
|
2
|
+
module RPC
|
3
|
+
module RequestHandler
|
4
|
+
def listunspent(min = 0, max = 999999, addresses: nil)
|
5
|
+
height = node.chain.latest_block.height
|
6
|
+
utxos = node.wallet.list_unspent(current_block_height: height, min: min, max: max, addresses: addresses)
|
7
|
+
utxos.map do |u|
|
8
|
+
{
|
9
|
+
tx_hash: u.tx_hash,
|
10
|
+
index: u.index,
|
11
|
+
value: u.value,
|
12
|
+
script_pubkey: u.script_pubkey,
|
13
|
+
confirmations: height - u.block_height
|
14
|
+
}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def listunspentinaccount(account_name, min = 0, max = 999999)
|
19
|
+
height = node.chain.latest_block.height
|
20
|
+
utxos = node.wallet.list_unspent(account_name: account_name, current_block_height: height, min: min, max: max)
|
21
|
+
utxos.map do |u|
|
22
|
+
{
|
23
|
+
tx_hash: u.tx_hash,
|
24
|
+
index: u.index,
|
25
|
+
value: u.value,
|
26
|
+
script_pubkey: u.script_pubkey,
|
27
|
+
confirmations: height - u.block_height
|
28
|
+
}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def listuncoloredunspentinaccount(account_name, min = 0, max = 999999)
|
33
|
+
height = node.chain.latest_block.height
|
34
|
+
utxos = node.wallet.list_uncolored_unspent(account_name: account_name, current_block_height: height, min: min, max: max)
|
35
|
+
utxos.map do |u|
|
36
|
+
{
|
37
|
+
tx_hash: u.tx_hash,
|
38
|
+
index: u.index,
|
39
|
+
value: u.value,
|
40
|
+
script_pubkey: u.script_pubkey,
|
41
|
+
confirmations: height - u.block_height
|
42
|
+
}
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def listcoloredunspentinaccount(account_name, asset_type = Bitcoin::Wallet::AssetFeature::AssetType::OPEN_ASSETS , asset_id = nil, min = 0, max = 999999)
|
47
|
+
height = node.chain.latest_block.height
|
48
|
+
assets = node.wallet.list_unspent_assets_in_account(asset_type, asset_id, account_name: account_name, current_block_height: height, min: min, max: max).map do |asset|
|
49
|
+
out_point = Bitcoin::OutPoint.new(asset.tx_hash, asset.index)
|
50
|
+
utxo = node.wallet.utxo_db.get_utxo(out_point)
|
51
|
+
next unless utxo
|
52
|
+
[asset, utxo]
|
53
|
+
end.compact
|
54
|
+
assets = assets.map do |(asset, utxo)|
|
55
|
+
{
|
56
|
+
tx_hash: utxo.tx_hash,
|
57
|
+
index: utxo.index,
|
58
|
+
value: utxo.value,
|
59
|
+
asset_type: asset.asset_type,
|
60
|
+
asset_id: asset.asset_id,
|
61
|
+
asset_quantity: asset.asset_quantity,
|
62
|
+
script_pubkey: utxo.script_pubkey,
|
63
|
+
confirmations: height - utxo.block_height
|
64
|
+
}
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def getbalance(account_name)
|
69
|
+
node.wallet.get_balance(account_name)
|
70
|
+
end
|
71
|
+
|
72
|
+
def getassetbalance(account_name, asset_type = Bitcoin::Wallet::AssetFeature::AssetType::OPEN_ASSETS , asset_id = nil)
|
73
|
+
node.wallet.get_asset_balance(asset_type, asset_id, account_name: account_name)
|
74
|
+
end
|
75
|
+
|
76
|
+
# create new bitcoin address for receiving payments.
|
77
|
+
def getnewaddress(account_name)
|
78
|
+
address = node.wallet.generate_new_address(account_name)
|
79
|
+
script = Bitcoin::Script.parse_from_addr(address)
|
80
|
+
pubkey_hash = script.witness_data[1].bth
|
81
|
+
node.filter_add(pubkey_hash)
|
82
|
+
address
|
83
|
+
end
|
84
|
+
|
85
|
+
def createaccount(account_name)
|
86
|
+
account = node.wallet.create_account(Bitcoin::Wallet::Account::PURPOSE_TYPE[:native_segwit], account_name)
|
87
|
+
account.to_h
|
88
|
+
rescue
|
89
|
+
{}
|
90
|
+
end
|
91
|
+
|
92
|
+
def signrawtransaction(account_name, payload)
|
93
|
+
tx = Bitcoin::Tx.parse_from_payload(payload.htb)
|
94
|
+
signed_tx = Bitcoin::Wallet::Signer.sign(node, account_name, tx)
|
95
|
+
{ hex: signed_tx.to_payload.bth }
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Bitcoin
|
2
|
+
module Wallet
|
3
|
+
class Base
|
4
|
+
attr_reader :utxo_db
|
5
|
+
|
6
|
+
def get_balance(account_name)
|
7
|
+
account = find_account(account_name)
|
8
|
+
return 0 unless account
|
9
|
+
utxo_db.get_balance(account)
|
10
|
+
end
|
11
|
+
|
12
|
+
def list_unspent(account_name: nil, current_block_height: 9999999, min: 0, max: 9999999, addresses: nil)
|
13
|
+
if account_name
|
14
|
+
account = find_account(account_name)
|
15
|
+
return [] unless account
|
16
|
+
utxo_db.list_unspent_in_account(account, current_block_height: current_block_height, min: min, max: max)
|
17
|
+
else
|
18
|
+
utxo_db.list_unspent(current_block_height: current_block_height, min: min, max: max, addresses: addresses)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def list_uncolored_unspent(account_name: nil, current_block_height: 9999999, min: 0, max: 9999999)
|
23
|
+
account = find_account(account_name)
|
24
|
+
return [] unless account
|
25
|
+
utxo_db.list_uncolored_unspent_in_account(account, current_block_height: current_block_height, min: min, max: max)
|
26
|
+
end
|
27
|
+
|
28
|
+
def get_asset_balance(asset_type, asset_id, account_name: nil, current_block_height: 9999999, min: 0, max: 9999999)
|
29
|
+
account = find_account(account_name)
|
30
|
+
return 0 unless account
|
31
|
+
utxo_db.get_asset_balance(asset_type, asset_id, account, current_block_height: current_block_height, min: min, max: max)
|
32
|
+
end
|
33
|
+
|
34
|
+
def list_unspent_assets_in_account(asset_type, asset_id, account_name: nil, current_block_height: 9999999, min: 0, max: 9999999)
|
35
|
+
account = find_account(account_name)
|
36
|
+
return [] unless account
|
37
|
+
utxo_db.list_unspent_assets_in_account(asset_type, asset_id, account, current_block_height: current_block_height, min: min, max: max)
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def initialize(wallet_id, path_prefix)
|
43
|
+
@path = "#{path_prefix}wallet#{wallet_id}/"
|
44
|
+
@db = Bitcoin::Wallet::DB.new(@path)
|
45
|
+
@wallet_id = wallet_id
|
46
|
+
@utxo_db = Bitcoin::Wallet::UtxoDB.new("#{path_prefix}utxo#{wallet_id}/")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
syntax = "proto3";
|
2
|
+
|
3
|
+
package bitcoin.grpc;
|
4
|
+
|
5
|
+
|
6
|
+
service Blockchain {
|
7
|
+
rpc WatchTxConfirmed(WatchTxConfirmedRequest) returns (stream WatchTxConfirmedResponse);
|
8
|
+
rpc WatchUtxo(WatchUtxoRequest) returns (stream WatchUtxoResponse);
|
9
|
+
rpc WatchToken(WatchTokenRequest) returns (stream WatchTokenResponse);
|
10
|
+
}
|
11
|
+
|
12
|
+
message WatchTxConfirmedRequest {
|
13
|
+
string tx_hash = 1;
|
14
|
+
uint32 confirmations = 2;
|
15
|
+
}
|
16
|
+
|
17
|
+
message WatchTxConfirmedResponse {
|
18
|
+
oneof event {
|
19
|
+
EventTxConfirmed confirmed = 1;
|
20
|
+
}
|
21
|
+
}
|
22
|
+
|
23
|
+
message WatchUtxoRequest {
|
24
|
+
}
|
25
|
+
|
26
|
+
message WatchUtxoResponse {
|
27
|
+
oneof event {
|
28
|
+
EventUtxoRegistered registered = 1;
|
29
|
+
EventUtxoSpent spent = 2;
|
30
|
+
}
|
31
|
+
}
|
32
|
+
|
33
|
+
message WatchTokenRequest {
|
34
|
+
bytes asset_type = 1;
|
35
|
+
}
|
36
|
+
|
37
|
+
message WatchTokenResponse {
|
38
|
+
oneof event {
|
39
|
+
EventTokenIssued issued = 1;
|
40
|
+
EventTokenTransfered transfered = 2;
|
41
|
+
EventTokenBurned burned = 3;
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
45
|
+
message WatchAssetIdAssignedRequest {
|
46
|
+
string tx_hash = 1;
|
47
|
+
string tx_payload = 2;
|
48
|
+
}
|
49
|
+
|
50
|
+
message EventTxConfirmed {
|
51
|
+
string tx_hash = 1;
|
52
|
+
string tx_payload = 2;
|
53
|
+
uint32 block_height = 3;
|
54
|
+
uint32 tx_index = 4;
|
55
|
+
uint32 confirmations = 5;
|
56
|
+
}
|
57
|
+
|
58
|
+
message EventUtxoRegistered {
|
59
|
+
string tx_hash = 1;
|
60
|
+
string tx_payload = 2;
|
61
|
+
Utxo utxo = 3;
|
62
|
+
}
|
63
|
+
|
64
|
+
message EventUtxoSpent {
|
65
|
+
string tx_hash = 1;
|
66
|
+
string tx_payload = 2;
|
67
|
+
Utxo utxo = 3;
|
68
|
+
}
|
69
|
+
|
70
|
+
message EventTokenIssued {
|
71
|
+
AssetOutput asset = 1;
|
72
|
+
}
|
73
|
+
|
74
|
+
message EventTokenTransfered {
|
75
|
+
AssetOutput asset = 2;
|
76
|
+
}
|
77
|
+
|
78
|
+
message EventTokenBurned {
|
79
|
+
AssetOutput asset = 3;
|
80
|
+
}
|
81
|
+
|
82
|
+
message Utxo {
|
83
|
+
string tx_hash = 1;
|
84
|
+
uint32 index = 2;
|
85
|
+
uint32 block_height = 3;
|
86
|
+
uint64 value = 4;
|
87
|
+
string script_pubkey = 5;
|
88
|
+
}
|
89
|
+
|
90
|
+
message AssetOutput {
|
91
|
+
bytes asset_type = 1;
|
92
|
+
string asset_id = 2;
|
93
|
+
uint64 asset_quantity = 3;
|
94
|
+
string tx_hash = 4;
|
95
|
+
uint32 index = 5;
|
96
|
+
uint32 block_height = 6;
|
97
|
+
}
|