bitcoinwatcher 1.0.1__py3-none-any.whl → 1.2.0__py3-none-any.whl
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.
- bitcoin/address_listener/address_listener.py +14 -44
- bitcoin/address_listener/simple_address_listener.py +3 -1
- bitcoin/models/__init__.py +0 -0
- bitcoin/models/address_tx_data.py +36 -0
- bitcoin/tests/data/__init__.py +0 -0
- bitcoin/tests/data/transactions.py +5 -0
- bitcoin/tests/test_address_listener.py +4 -2
- bitcoin/tests/test_bitcoin_utils.py +32 -0
- bitcoin/utils/benchmark.py +33 -0
- bitcoin/utils/bitcoin_rpc.py +31 -0
- bitcoin/utils/bitcoin_utils.py +14 -12
- bitcoin/utils/tx_address_data_extractor.py +76 -0
- {bitcoinwatcher-1.0.1.dist-info → bitcoinwatcher-1.2.0.dist-info}/METADATA +2 -1
- bitcoinwatcher-1.2.0.dist-info/RECORD +26 -0
- bitcoinwatcher-1.0.1.dist-info/RECORD +0 -18
- {bitcoinwatcher-1.0.1.dist-info → bitcoinwatcher-1.2.0.dist-info}/LICENSE +0 -0
- {bitcoinwatcher-1.0.1.dist-info → bitcoinwatcher-1.2.0.dist-info}/WHEEL +0 -0
- {bitcoinwatcher-1.0.1.dist-info → bitcoinwatcher-1.2.0.dist-info}/top_level.txt +0 -0
@@ -1,10 +1,12 @@
|
|
1
1
|
from unittest import TestCase
|
2
2
|
|
3
|
-
from bitcoin.address_listener.address_listener import AbstractAddressListener, AddressTxData
|
3
|
+
from bitcoin.address_listener.address_listener import AbstractAddressListener, AddressTxData
|
4
|
+
from bitcoin.models.address_tx_data import AddressTxType
|
4
5
|
|
5
6
|
|
6
7
|
class DummyAddressListener(AbstractAddressListener):
|
7
|
-
|
8
|
+
|
9
|
+
def consume(self, subscribed_address, address_tx_data: [AddressTxData]):
|
8
10
|
pass
|
9
11
|
|
10
12
|
def __init__(self, address_to_listen: [str]):
|
@@ -0,0 +1,32 @@
|
|
1
|
+
from unittest import TestCase
|
2
|
+
|
3
|
+
from bitcoinlib.transactions import Transaction
|
4
|
+
|
5
|
+
from bitcoin.tests.data.transactions import batch_airdrop_tx_hex, tx_hex, non_reveal_tx_hex
|
6
|
+
from bitcoin.utils.bitcoin_utils import is_reveal_tx, count_reveal_inputs
|
7
|
+
|
8
|
+
|
9
|
+
class Test(TestCase):
|
10
|
+
def test_is_reveal_tx(self):
|
11
|
+
tx = Transaction.parse_hex(tx_hex, strict=False)
|
12
|
+
self.assertTrue(is_reveal_tx(tx))
|
13
|
+
|
14
|
+
def test_is_reveal_tx_in_second_input(self):
|
15
|
+
tx = Transaction.parse_hex(batch_airdrop_tx_hex, strict=False)
|
16
|
+
self.assertTrue(is_reveal_tx(tx))
|
17
|
+
|
18
|
+
def test_is_not_reveal_tx(self):
|
19
|
+
tx = Transaction.parse_hex(non_reveal_tx_hex, strict=False)
|
20
|
+
self.assertFalse(is_reveal_tx(tx))
|
21
|
+
|
22
|
+
def test_count_reveal_inputs(self):
|
23
|
+
tx = Transaction.parse_hex(tx_hex, strict=False)
|
24
|
+
self.assertEqual(count_reveal_inputs(tx), 1)
|
25
|
+
|
26
|
+
def test_count_reveal_inputs_not_reveal(self):
|
27
|
+
tx = Transaction.parse_hex(non_reveal_tx_hex, strict=False)
|
28
|
+
self.assertEqual(count_reveal_inputs(tx), 0)
|
29
|
+
|
30
|
+
def test_count_reveal_in_airdrop_tx(self):
|
31
|
+
tx = Transaction.parse_hex(batch_airdrop_tx_hex, strict=False)
|
32
|
+
self.assertEqual(count_reveal_inputs(tx), 1420)
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# benchmark between mempool and bitcoinrcp get transaction info
|
2
|
+
import os
|
3
|
+
import time
|
4
|
+
import requests
|
5
|
+
from ordipool.ordipool.mempoolio import Mempool
|
6
|
+
|
7
|
+
from bitcoin.utils.bitcoin_rpc import BitcoinRPC
|
8
|
+
from bitcoin.utils.constants import default_host
|
9
|
+
|
10
|
+
host = os.environ.get("RPC_HOST", default_host)
|
11
|
+
base_url = f"http://{host}:3006/api"
|
12
|
+
|
13
|
+
mempool = Mempool(base_url)
|
14
|
+
bitcoinrpc = BitcoinRPC()
|
15
|
+
|
16
|
+
if __name__ == '__main__':
|
17
|
+
|
18
|
+
txid = 'a6293e898b056fbea0329d071b1b237e4449ff464cdbc7a9ed8a770b97aafd4c'
|
19
|
+
times = 1000
|
20
|
+
start = time.time()
|
21
|
+
print("mempool starting")
|
22
|
+
for i in range(times):
|
23
|
+
print(i)
|
24
|
+
mempool.get_transaction(txid)
|
25
|
+
end = time.time()
|
26
|
+
print(f"mempool took: {end - start}")
|
27
|
+
|
28
|
+
start = time.time()
|
29
|
+
for i in range(times):
|
30
|
+
bitcoinrpc.get_transaction(txid)
|
31
|
+
end = time.time()
|
32
|
+
print(f"bitcoinrpc took: {end - start}")
|
33
|
+
|
@@ -0,0 +1,31 @@
|
|
1
|
+
import os
|
2
|
+
|
3
|
+
from bitcoinrpc.authproxy import AuthServiceProxy, JSONRPCException
|
4
|
+
|
5
|
+
from bitcoin.utils.constants import default_host
|
6
|
+
|
7
|
+
|
8
|
+
class BitcoinRPC:
|
9
|
+
rpc_user = os.environ.get("RPC_USER")
|
10
|
+
rpc_password = os.environ.get("RPC_PASSWORD")
|
11
|
+
rpc_host = os.environ.get("RPC_HOST", default_host)
|
12
|
+
rpc_port = os.environ.get("RPC_PORT", 8332)
|
13
|
+
rpc_connection: AuthServiceProxy
|
14
|
+
|
15
|
+
def __init__(self):
|
16
|
+
rpc_string = f"http://{self.rpc_user}:{self.rpc_password}@{self.rpc_host}:{self.rpc_port}"
|
17
|
+
print("rpc_string: ", rpc_string)
|
18
|
+
self.rpc_connection = AuthServiceProxy(rpc_string)
|
19
|
+
|
20
|
+
def get_transaction(self, txid: str) -> dict:
|
21
|
+
return self.rpc_connection.getrawtransaction(txid, True)
|
22
|
+
|
23
|
+
|
24
|
+
if __name__ == '__main__':
|
25
|
+
rpc = BitcoinRPC()
|
26
|
+
txid = 'a6293e898b056fbea0329d071b1b237e4449ff464cdbc7a9ed8a770b97aafd4c'
|
27
|
+
try:
|
28
|
+
transaction = rpc.get_transaction(txid)
|
29
|
+
print(transaction)
|
30
|
+
except JSONRPCException as e:
|
31
|
+
print(f"An error occurred: {e}")
|
bitcoin/utils/bitcoin_utils.py
CHANGED
@@ -1,16 +1,18 @@
|
|
1
|
-
from
|
2
|
-
from
|
3
|
-
from bitcoinutils.transactions import TxOutput
|
1
|
+
from bitcoinlib.transactions import Transaction, Input
|
2
|
+
from ordipool.utils.utils import convert_to_hex
|
4
3
|
|
5
4
|
|
6
|
-
def
|
7
|
-
|
8
|
-
#
|
9
|
-
|
10
|
-
return txid_hex
|
5
|
+
def count_inscriptions(vin: Input) -> int:
|
6
|
+
ord_hex = convert_to_hex('ord')
|
7
|
+
# count occurences of ord in the witness script
|
8
|
+
return sum([witness.hex().count(ord_hex) for witness in vin.witnesses])
|
11
9
|
|
12
10
|
|
13
|
-
def
|
14
|
-
|
15
|
-
|
16
|
-
|
11
|
+
def count_reveal_inputs(tx: Transaction) -> int:
|
12
|
+
return sum([count_inscriptions(vin) for vin in tx.inputs])
|
13
|
+
|
14
|
+
|
15
|
+
def is_reveal_tx(tx: Transaction) -> bool:
|
16
|
+
count_of_inscriptions = count_reveal_inputs(tx)
|
17
|
+
return count_of_inscriptions > 0
|
18
|
+
# check if any of the witness contains ord, convert witness to hex
|
@@ -0,0 +1,76 @@
|
|
1
|
+
from abc import ABC, abstractmethod
|
2
|
+
|
3
|
+
|
4
|
+
from bitcoinlib.transactions import Transaction
|
5
|
+
from ordipool.ordipool.mempoolio import Mempool
|
6
|
+
|
7
|
+
from bitcoin.address_listener.address_listener import AddressTxData
|
8
|
+
from bitcoin.models.address_tx_data import AddressTxType, TransactionStatus
|
9
|
+
from bitcoin.utils.bitcoin_utils import is_reveal_tx, count_reveal_inputs
|
10
|
+
|
11
|
+
|
12
|
+
class AbstractTxAddressDataExtractor(ABC):
|
13
|
+
@abstractmethod
|
14
|
+
def extract(self, tx: Transaction) -> [AddressTxData]:
|
15
|
+
pass
|
16
|
+
|
17
|
+
|
18
|
+
class MempoolTxAddressDataExtractor(AbstractTxAddressDataExtractor):
|
19
|
+
mempool: Mempool
|
20
|
+
|
21
|
+
def __init__(self, mempool: Mempool):
|
22
|
+
self.mempool = mempool
|
23
|
+
|
24
|
+
def extract(self, tx: Transaction) -> [AddressTxData]:
|
25
|
+
outputs = tx.outputs
|
26
|
+
tx_id = tx.txid
|
27
|
+
has_inscriptions = is_reveal_tx(tx)
|
28
|
+
|
29
|
+
tx = self.mempool.get_transaction(tx_id)
|
30
|
+
tx_status = TransactionStatus.CONFIRMED if tx.confirmed else TransactionStatus.UNCONFIRMED
|
31
|
+
address_tx_data = []
|
32
|
+
# getting inputs data separately from mempool
|
33
|
+
# as current library doesn't provide rich data like previous outputs and its value
|
34
|
+
for vin in tx.vins:
|
35
|
+
address = vin.prev_out.address
|
36
|
+
amount = vin.prev_out.value
|
37
|
+
address_tx_data.append(AddressTxData(tx_status=tx_status.value,
|
38
|
+
address=address,
|
39
|
+
is_reveal_tx=has_inscriptions,
|
40
|
+
type=AddressTxType.INPUT,
|
41
|
+
_amount=amount,
|
42
|
+
tx_id=tx_id))
|
43
|
+
for output in outputs:
|
44
|
+
amount = output.value
|
45
|
+
address_tx_data.append(AddressTxData(tx_status=tx_status.value,
|
46
|
+
address=output.address,
|
47
|
+
_amount=amount,
|
48
|
+
is_reveal_tx=has_inscriptions,
|
49
|
+
type=AddressTxType.OUTPUT,
|
50
|
+
tx_id=tx_id))
|
51
|
+
|
52
|
+
return address_tx_data
|
53
|
+
|
54
|
+
|
55
|
+
class DefaultTxAddressDataExtractor(AbstractTxAddressDataExtractor):
|
56
|
+
def extract(self, tx: Transaction) -> [AddressTxData]:
|
57
|
+
outputs = tx.outputs
|
58
|
+
address_tx_data = []
|
59
|
+
inputs = tx.inputs
|
60
|
+
tx_status = tx.status
|
61
|
+
for input in inputs:
|
62
|
+
address = input.address
|
63
|
+
amount = 0
|
64
|
+
address_tx_data.append(AddressTxData(tx_status=tx_status,
|
65
|
+
address=address,
|
66
|
+
type=AddressTxType.INPUT,
|
67
|
+
_amount=amount,
|
68
|
+
tx_id=tx.txid))
|
69
|
+
for output in outputs:
|
70
|
+
amount = output.value
|
71
|
+
address_tx_data.append(AddressTxData(tx_status=tx_status,
|
72
|
+
address=output.address,
|
73
|
+
_amount=amount,
|
74
|
+
type=AddressTxType.OUTPUT,
|
75
|
+
tx_id=tx.txid))
|
76
|
+
return address_tx_data
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: bitcoinwatcher
|
3
|
-
Version: 1.0
|
3
|
+
Version: 1.2.0
|
4
4
|
Summary: bitcoinwatcher is a Python library that implements a ZMQ subscriber and provides abstractions to build custom address watchers. This library is designed to make it easy for developers to monitor Bitcoin addresses and react to changes in their state.
|
5
5
|
Author: twosatsmaxi
|
6
6
|
License: Apache License
|
@@ -227,6 +227,7 @@ Requires-Dist: six ==1.16.0
|
|
227
227
|
Requires-Dist: urllib3 ==2.2.1
|
228
228
|
Requires-Dist: bitcoinlib ==0.6.14
|
229
229
|
Requires-Dist: ordipool ==1.2.0
|
230
|
+
Requires-Dist: python-bitcoinrpc ==1.0
|
230
231
|
|
231
232
|
# bitcoinwatcher
|
232
233
|
|
@@ -0,0 +1,26 @@
|
|
1
|
+
bitcoin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
+
bitcoin/address_listener/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3
|
+
bitcoin/address_listener/address_listener.py,sha256=sK0hrhPrYg8z6AC8MqNbF3UoaqvbhdhVcoyMLj8x4MQ,2223
|
4
|
+
bitcoin/address_listener/simple_address_listener.py,sha256=iSMPBUzl9d4s8_ee2LAXz83zBiGfs1KhwSH_7FvxwKY,1609
|
5
|
+
bitcoin/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
6
|
+
bitcoin/models/address_tx_data.py,sha256=0zIleuEHern42zk1Pp7IteR5jQqVdAM1l4Gvy6YzGe0,754
|
7
|
+
bitcoin/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
8
|
+
bitcoin/tests/test_address_listener.py,sha256=oqVfJ_lQNHgRxCnDteUpkaUyHff5Wa8J2oYJnwQ-QaE,3113
|
9
|
+
bitcoin/tests/test_bitcoin_utils.py,sha256=NYRHWfqaOgLO8osOYVqRudk9ksuhC3LC9HGrxj-VGu4,1213
|
10
|
+
bitcoin/tests/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
11
|
+
bitcoin/tests/data/transactions.py,sha256=To0FCF4JDdjZTV9H900WCuV8_mGPItk5bEiYgUj0KiY,394877
|
12
|
+
bitcoin/tx_listener/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
13
|
+
bitcoin/tx_listener/abstract_tx_listener.py,sha256=rGp9na-aOSl_aPaIqf44RTZaFF3SvrxIhZBujTnWqao,189
|
14
|
+
bitcoin/tx_listener/zmq_listener.py,sha256=_edaee2PYj9T1jxLenv68ekZRTM8-LUN3DloDLNQ5Bc,999
|
15
|
+
bitcoin/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
16
|
+
bitcoin/utils/benchmark.py,sha256=ZCfhIe4_meUNpQ7NEioZj3_uudCisg7J8d_LTMoRFto,875
|
17
|
+
bitcoin/utils/bitcoin_rpc.py,sha256=Uq3eZnLaGOgltybEWeBRubnUhTHyB8gVI_L_SnrZ-ug,1012
|
18
|
+
bitcoin/utils/bitcoin_utils.py,sha256=mrnRPqUa2U2EMKu7rrPV_bW1sL2CJUfbAom0Zdamydk,631
|
19
|
+
bitcoin/utils/constants.py,sha256=irZLlArgica2VckyckEYxH5D5KjvdF52dtBMWswqw8k,52
|
20
|
+
bitcoin/utils/inscription_utils.py,sha256=8QbOJ1o1n1bMFsPREGLzwFjnGzfuARgJCPr6ORhP44o,193
|
21
|
+
bitcoin/utils/tx_address_data_extractor.py,sha256=M_WvBNNXYwd2qBG6oyfu8Vn6P8F0Rt5w1FnfvFO6IZc,3321
|
22
|
+
bitcoinwatcher-1.2.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
23
|
+
bitcoinwatcher-1.2.0.dist-info/METADATA,sha256=i4U1BiZn-KQ9TQDPKGaKkctAFpgx1lRGaLywjvz5qoc,14940
|
24
|
+
bitcoinwatcher-1.2.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
25
|
+
bitcoinwatcher-1.2.0.dist-info/top_level.txt,sha256=YdUgzLdCiMlrwaKyDqHA1acEd23QFko5bv7D6nBANJ0,8
|
26
|
+
bitcoinwatcher-1.2.0.dist-info/RECORD,,
|
@@ -1,18 +0,0 @@
|
|
1
|
-
bitcoin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
-
bitcoin/address_listener/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3
|
-
bitcoin/address_listener/address_listener.py,sha256=WKDG8gtB9_2K-v0nYhkKDkaqxPz2uE2uVtwWRNzg7H8,3000
|
4
|
-
bitcoin/address_listener/simple_address_listener.py,sha256=2qR012t3rHTNHkit6TvkYP9Co4IVySKG8YyzmxKc0cU,1499
|
5
|
-
bitcoin/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
6
|
-
bitcoin/tests/test_address_listener.py,sha256=_8ic7ldHaeICfYTepAkqcWFzZPhEKzbIkAfrAZ1ZdCs,3033
|
7
|
-
bitcoin/tx_listener/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
8
|
-
bitcoin/tx_listener/abstract_tx_listener.py,sha256=rGp9na-aOSl_aPaIqf44RTZaFF3SvrxIhZBujTnWqao,189
|
9
|
-
bitcoin/tx_listener/zmq_listener.py,sha256=_edaee2PYj9T1jxLenv68ekZRTM8-LUN3DloDLNQ5Bc,999
|
10
|
-
bitcoin/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
11
|
-
bitcoin/utils/bitcoin_utils.py,sha256=ehzfwiuln_lPia6urtUSVE3zXC1zyZEKiNM36e7N00k,428
|
12
|
-
bitcoin/utils/constants.py,sha256=irZLlArgica2VckyckEYxH5D5KjvdF52dtBMWswqw8k,52
|
13
|
-
bitcoin/utils/inscription_utils.py,sha256=8QbOJ1o1n1bMFsPREGLzwFjnGzfuARgJCPr6ORhP44o,193
|
14
|
-
bitcoinwatcher-1.0.1.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
15
|
-
bitcoinwatcher-1.0.1.dist-info/METADATA,sha256=qpqrssZZ60vtfPxx3vziTyZ5krWFVQz1Y86PYs8JmH4,14901
|
16
|
-
bitcoinwatcher-1.0.1.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
17
|
-
bitcoinwatcher-1.0.1.dist-info/top_level.txt,sha256=YdUgzLdCiMlrwaKyDqHA1acEd23QFko5bv7D6nBANJ0,8
|
18
|
-
bitcoinwatcher-1.0.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|