-
Notifications
You must be signed in to change notification settings - Fork 179
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor and cleanup of blockchaininterface and related #1462
Refactor and cleanup of blockchaininterface and related #1462
Conversation
So far have tested locally that tests are passing. Next is to do some more manual testing with signet / testnet. But anyway would be good to have some feedback. |
0344165
to
b70d07a
Compare
Completed a first round of reading review. Apart from the issues raised, otherwise it seems good to me. I think #1461 should be tested and merged first, since there is a demand from users for that. (Mentioning it because they will conflict). Related point, since this change is very big and invasive, we really need to test it a lot with all the various usage modes, before we merge it. |
Switched my public orderbook mirror (http://nnuifroxn5aolsqa2svedcskojlqfp2ygt4u42ac7njehsbemagpwiqd.onion/) to this code. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just skimmed through, will try to look more into this.
Since we are touching, we could reformat the entire file with some linter (I still see some PEP8 complaints). Anyway, nbd.
@@ -689,7 +692,7 @@ def listunspent(self): | |||
"amount": u["amount"] | |||
} for u in self.scan_result["unspents"]] | |||
|
|||
def set_wallet_no_history(self, wallet): | |||
def set_wallet_no_history(self, wallet) -> None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could add typehint for wallet
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tried to do that, but ran into problem and don't want to spend too much time just on a single typehint.
It should be BaseWallet
, which requires moving INF_HEIGHT
out from blockchaininterface, so that there is no circular imports and we can from jmclient.wallet import BaseWallet
, ended up with some strange errors in tests, couldn't figure out:
self = <test_payjoin.TrialTestPayjoin1 testMethod=test_payment>
def tearDown(self):
for dc in reactor.getDelayedCalls():
dc.cancel()
res = final_checks(self.wallet_services, self.cj_amount,
> self.manager.final_psbt.get_fee(),
self.ssb, self.rsb)
E AttributeError: 'TrialTestPayjoin1' object has no attribute 'manager'
jmclient/test/test_payjoin.py:133: AttributeError
And flake8
doesn't like forward references, which could be an alternative solution.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed not to waste too much time. If you want to try one last time, it seems to work for me locally using:
from __future__ import annotations # at the very top
# <-- Additional import.
import typing
if typing.TYPE_CHECKING:
from jmclient.wallet import BaseWallet
I could try splitting off some parts of this PR into smaller PRs, so that it's easier to review and test. For example, fee estimation code changes. |
This seems to make a lot of sense. One file or group of files at a time. |
3805c7a Remove ElectrumWalletInterface (Kristaps Kaupe) Pull request description: Remove broken `ElectrumWalletInterface` (we can re-introduce it later from history if somebody wants to fix it). Part of splitting #1462 into smaller PRs for easier testing and reviews. ACKs for top commit: AdamISZ: tACK 3805c7a Tree-SHA512: 8d11f3488c5e16058be187212b49e2cf11787b5fb9a1bb87f8949f76fa1569358932bea5bcf4fa3d0b0640534d87681d762b6e595f85a8e02584c9e438960c66
Another failure of abstraction that needs to be addressed - joinmarket-clientserver/jmclient/jmclient/wallet_utils.py Lines 506 to 510 in 71c0a84
|
…etwalletinfo()` for `bci` e31e839 Add get_wallet_rescan_status() instead of getwalletinfo() for bci (Kristaps Kaupe) Pull request description: Noticed this when tried to rebase #1462 after merging of #1477. #1461 added public `getwalletinfo()` method to `BitcoinCoreInterface`, which was used by code outside of `jmclient/jmclient/blockchaininterface.py`. This is bad approach, as it relies on Bitcoin Core RPC `getwalletinfo` returned `dict`, which contains a lots of different stuff too, could lead to more problems in future introducing other blockchain interface classes. Let's instead have generic method returning just wallet rescan status. Also it now returns `Tuple[bool, Optional[Decimal]]` with rescan status percentage, if rescan is in progress, although that's not used by any other code for now. ACKs for top commit: AdamISZ: utACK e31e839 , very much agree with the thinking here. Tree-SHA512: 2d8c9b8157847e713838099d0f62dfcd5321c9498cf8453a9087407e2cd9c32906739c8e71460fc6ac6426662d2ac501261080fea08388d928933f788bda9a8d
b70d07a
to
b43577c
Compare
Rebased |
b43577c
to
24af7c9
Compare
Rebased against master to re-run CI with latest fixes. |
cb8bfc6
to
3f81323
Compare
Rebased |
1ef2ea5
to
f8ad8c1
Compare
d5c240b Refactor fee estimation code (Kristaps Kaupe) Pull request description: Part of splitting #1462 into smaller PRs for easier reviewing and testing. Top commit has no ACKs. Tree-SHA512: af1d75881ac7736c46ae8ac96a50808558b626c92f52ee290e68eb19d2e317d0e46c553f7087ed609788611c00de3c3783bf8246e7286da63673212a7f102b25
f8ad8c1
to
5249ea5
Compare
Rebased |
e52b894
to
c51f349
Compare
I think I have addressed or responded to all review comments. |
Testing on 16a221a ; first, current master, then, that commit (i.e. this PR):
Thus these are errors introduced by the PR. The errors all appear to be fee estimation related:
... these errors don't only appear in the |
Will look at this! Apparently, some commit I added today causes this. |
Ok, I'm giving up for today, will look at it again later. I cannot understand how this error can happen as after #1504 changes
|
So far this is proving to be quite tricky. On this PR, 16a221a: run On master, 54db582 : |
It also fails now with dd86234, where previously there were no CI errors... |
The problem is here: joinmarket-clientserver/jmclient/jmclient/blockchaininterface.py Lines 292 to 298 in 16a221a
in master, there is a following joinmarket-clientserver/jmclient/jmclient/blockchaininterface.py Lines 135 to 148 in d5c240b
Not sure why it's missing, but without it we just return |
Thanks! Failure to rebase from my side, |
tACK 92060eb Tested: manual spends, individual coinjoins, and tumbler operation. Also ran test suite ofc. Not currently seeing any problems, though, no objection if you still need to clean some details up. Also reminder to squash before merge. Thanks. |
@PulpCattel Care to take another look at this? |
Looking at it now. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tests pass, but I didn't test much manually other than basic send.
return len(self._rpc('getaddressinfo', [addr])['labels']) > 0 | ||
|
||
def get_block(self, blockheight): | ||
def get_block(self, blockheight: int) -> Optional[str]: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question in dd86234:
Is Optional
correct here? I see that a few methods (e.g., this one or get_transaction()
) use Optional
, but many others don't.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't see any reason for Optional here. The function misses error checking (what if get block hash fails), but that's orthogonal to typehints, also, this has only ever been used for blockchain scanning so far.
I suppose there's an argument for Optional based on an idea of None being used as the return type for failure? But that's just imagined, not actual. I'd just have str only, since that's the function's intent, and exception classes can handle failures.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree, addressed in 094df20.
def import_addresses(self, addr_list: List[str], wallet_name: str, | ||
restart_cb: Callable[[str], None] = None) -> None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In dd86234:
addr_list
can receive a set
. For example import_addresses_if_needed()
below would pass a set
to it. But I see that in other places is called with a list
.
IDK how convenient it is to use set
everywhere, or we could change this to Iterable[str]
or Union[List[str], Set[str]]
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Iterable
seems nicer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed in 52b007e.
def get_current_block_height(self) -> int: | ||
try: | ||
res = self._rpc("getblockcount", []) | ||
return self._rpc("getblockcount", []) | ||
except JsonRpcError as e: | ||
log.error("Getblockcount RPC failed with: %i, %s" % ( | ||
raise RuntimeError("Getblockcount RPC failed with: %i, %s" % ( | ||
e.code, e.message)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
General note/unrelated to this PR:
It is a bit weird that this is the only method checking for JsonRpcError
.
I see the check was added in a2aafd2 with the idea of eventually improving this. Maybe we could leave a TODO
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be addressed separately IMO.
@@ -689,7 +692,7 @@ def listunspent(self): | |||
"amount": u["amount"] | |||
} for u in self.scan_result["unspents"]] | |||
|
|||
def set_wallet_no_history(self, wallet): | |||
def set_wallet_no_history(self, wallet) -> None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed not to waste too much time. If you want to try one last time, it seems to work for me locally using:
from __future__ import annotations # at the very top
# <-- Additional import.
import typing
if typing.TYPE_CHECKING:
from jmclient.wallet import BaseWallet
jmclient/jmclient/jsonrpc.py
Outdated
Send an appropriate HTTP query to the server. The JSON-RPC | ||
request should be (as object) in 'obj'. If the call succeeds, | ||
the resulting JSON object is returned. In case of an error | ||
with the connection (not JSON-RPC itself), an exception is raised. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit in dd86234:
Extra spaces
Send an appropriate HTTP query to the server. The JSON-RPC | |
request should be (as object) in 'obj'. If the call succeeds, | |
the resulting JSON object is returned. In case of an error | |
with the connection (not JSON-RPC itself), an exception is raised. | |
Send an appropriate HTTP query to the server. The JSON-RPC | |
request should be (as object) in 'obj'. If the call succeeds, | |
the resulting JSON object is returned. In case of an error | |
with the connection (not JSON-RPC itself), an exception is raised. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed in 60b8923.
jmclient/jmclient/wallet_service.py
Outdated
@@ -964,7 +964,7 @@ def get_internal_addr(self, mixdepth): | |||
self.import_addr(addr) | |||
return addr | |||
|
|||
def collect_addresses_init(self): | |||
def collect_addresses_init(self) -> Set[str]: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In c51f349:
This method returns return addresses, saved_indices
, my IDE says it's Tuple[Set[str], Dict[int, List[int]]]
def collect_addresses_init(self) -> Set[str]: | |
def collect_addresses_init(self) -> Tuple[Set[str], Dict[int, List[int]]]: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed in d80d8b6.
Addressed review comments. |
@AdamISZ @PulpCattel Any more comments? I would like to merge this soon. |
Taking a look now, just to sanity check everything. |
tACK d80d8b6 Squash before merging reminder :) |
Summary of changes: * Add typehints to blockchaininterface.py and jsonrpc.py; * Move all methods called by external code to BlockchainInterface base class or add abstract methods there; * More dummy abstract method overrides for DummyBlockchainInterface (for tests); * Alphabetical ordering of imports and other minor stuff; * Behaviour change - previously fee estimation would fail if it could not get mempoolminfee, now will go with default 10 sat/vB. Co-authored-by: Pulp <[email protected]>
d80d8b6
to
3fc74fb
Compare
Summary of changes:
jmclient/jmclient/blockchaininterface.py
andjmclient/jmclient/jsonrpc.py
;BlockchainInterface
base class or add abstract methods there;Remove broken(done in RemoveElectrumWalletInterface
(we can re-introduce it later from history if somebody wants to fix it);ElectrumWalletInterface
#1477)DummyBlockchainInterface
(for tests);#1460 was part of this, but did separate PR for that one, as it is simpler to review small refactoring changes.
This should make it more easy to: 1) write new code that uses blockchaininterface, 2) write new alternative implementations of
BlockchainInterface
.