-
Notifications
You must be signed in to change notification settings - Fork 188
Add support for wallet
send
, sendmany
, sign
, open
, and close
#726
Add support for wallet
send
, sendmany
, sign
, open
, and close
#726
Conversation
refactor `send`, `sendmany`, and `sign`
- reactor open and close and add support for send, sendmany, and sign
- add support for `CommandWalletClose` and update for refactoring
- update for `make lint`
- update for `make lint`
- update CommandWalletClose
- update to match CityOfZion#725 and also allow for subcommands to execute without arguments
- update to match CityOfZion#725 and update CommandWalletClose.execute() w/o arguments
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.
But please check my implementation to see if I am on the right track.
Yes, only a few nitpicks but the general implementation is the way to go.
Thank you for fixing the self.Wallet
and other things that had to moved to PromptData
!
neo/Prompt/Commands/Wallet.py
Outdated
self.execute_sub_command(item, arguments[1:]) | ||
return | ||
|
||
elif item == 'close': |
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.
Can't close
be done with other subcommands because it needs a wallet to be opened?
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.
I don't think so because this follows the original implementation (i.e. wallet close
closes the open 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.
CommandWalletClose.execute
starts with if PromptData.Wallet:
.
The difference will be that instead of silently doing nothing if no wallet is opened, it would print a 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.
I guess I am not understanding 🙁 Could you message me on Discord or show me what you mean?
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.
You added close
as a "specially handled command" instead of a "normal command".
So for now, there is
elif item == 'close':
self.execute_sub_command(item)
return
before
if not wallet:
print("Please open a wallet")
return
If you do not handle close
a special way, it would be handled in
try:
self.execute_sub_command(item, arguments[1:])
except KeyError:
print(f"Wallet: {item} is an invalid parameter")
Therefore we would have the 2 cases:
- a wallet is opened: works as now
- no wallet is opened:
print("Please open a wallet")
would be executed instead of nothing.
The complete implementation of execute()
could be:
def execute(self, arguments):
wallet = PromptData.Wallet
item = get_arg(arguments)
# Create and Open must be handled specially.
if item in {'create', 'open'}:
self.execute_sub_command(item, arguments[1:])
return
if not wallet:
print("Please open a wallet")
return
if not item:
print("Wallet %s " % json.dumps(wallet.ToJson(), indent=4))
return
try:
self.execute_sub_command(item, arguments[1:])
except KeyError:
print(f"Wallet: {item} is an invalid parameter")
If it is still not clear (I don't find a good way to explain), let's talk on Discord later on.
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.
Okay, I think I understand. You are saying to just keep close
as a normal subcommand. Okay. Lemme see what I can do. Thank you for explaining! 🙏
neo/Prompt/Commands/Wallet.py
Outdated
if item == 'create': | ||
self.execute_sub_command(item, arguments[1:]) | ||
return | ||
|
||
elif item == 'open': |
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 regroup all the commands in a set
and check if item in xxx
. (if close
can be moved out, see after)
neo/Prompt/Commands/Wallet.py
Outdated
def __init__(self): | ||
super().__init__() | ||
|
||
@classmethod |
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 not be @classmethod
and use self
instead of cls
.
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.
for compatibility
for compatibility
for compatibility
for compatibility
Improve CommandBase.register_sub_command to use the subcommand's Comm…
- update CommandWalletClose
- remove redundant logic
- add tests to show normal functionality
- add functionality for subcommands without arguments
What do you guys think of the method of testing I implemented? I could continue this method of testing for the other methods introduced to ensure coverage is maintained as much as possible while refactoring is completed. NOTE: Coverage for |
- re-add comment
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.
I left a few more comments, please let me know what you think.
What do you guys think of the method of testing I implemented?
It looks good to me but I think @ixje should confirm because I haven't looked at the tests before.
neo/Prompt/Commands/Wallet.py
Outdated
super().__init__() | ||
|
||
def execute(self): | ||
if PromptData.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.
Maybe the implementation could be moved to a static method or to PromptData.
It could avoid having to instanciate CommandWalletClose to call execute. (CommandWalletClose().execute()
in prompt.py).
What do you think?
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.
This is why I originally had it as a class method. But changed it after your review. Couldn't we just keep it as a class method?
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.
A static method still required me to instantiate the class
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.
I realize that my message was probably confusing, sorry for that.
I was suggesting to keep execute as is (to override execute(self arguments)
) and have it call another static method.
Imo a @classmethod
should only be used when you want to override it in a child class or when you need to have access to cls
.
I think the following should work:
class CommandWalletClose(CommandBase):
...
def execute(self, arguments=None):
CommandWalletClose.close_wallet()
@staticmethod
def close_wallet():
if not PromptData.Wallet:
return False
path = PromptData.Wallet._path
PromptData.Prompt.stop_wallet_loop()
PromptData.Wallet.Close()
PromptData.Wallet = None
print("Closed wallet %s" % path)
return True
It should be possible to call it with CommandWalletClose.close_wallet()
.
I think it would be even better to have this function in PromptData
and call PromptData.close_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.
@LysanderGG Thank you. I will give it a shot. I will try it your preferred way.
neo/Prompt/CommandBase.py
Outdated
def execute_sub_command(self, id, arguments): | ||
self.__sub_commands[id].execute(arguments) | ||
def execute_sub_command(self, id, arguments=None): | ||
if arguments is not 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 my opinion, the original signature execute(self, arguments)
should be respected. None could be given as arguments for commands like CommandWalletClose
.
if info['address'] == self.watch_addr_str: | ||
transfers += 1 | ||
self.assertEqual(2, transfers) | ||
self.assertIn("Relayed Tx", mock_print.getvalue()) |
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.
the execute()
method does not have an enforced return type. Use this to your advantage to return the normal res
value from process_transaction
as in the original tests
here
this way you don't have to patch stdout
and you have far more options for testing correct behaviour. We now threw away good logic in favour of trusting a printed message indicating all went right.
Note that the actual goal isn't coverage. The goal is testing correct behaviour of the functions/modules under different circumstances. coverage
is just an indicator that can tell you if you missed any obvious parts in your test scenario's.
- Not having full coverage does indicate you've not tested all scenario's.
- Having full coverage does not indicate you have tested all scenario's.
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.
I tried this originally and all it ever returned was None
. Also pylint
warned about it in VSC. Do you have any hints?
This is why I moved the test logic to the next test. So, this basic test shows everything works and then I test the original functions thoroughly because they return values other than 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.
@LysanderGG if you read my comment above you see I assumed we could use the return value of execute()
. Atm this doesn't work because for the CommandBase.execute_sub_command
doesn't return the value. Do you see/have any objections for changing the behaviour of that? I don't have a full clear mind at this point to see possible limitations and you know this code the best :)
If we return the results of execute
commands they become more obvious to test. The other approach is just directly calling a the command class. An example test of the former is:
args = ['send', 'neo', self.watch_addr_str, '50']
command_wallet = Wallet.CommandWallet()
res = command_wallet.execute(args)
an example of the latter is
args = ['neo', self.watch_addr_str, '50']
command_wallet_send = Wallet.CommandWalletSend()
res = command_wallet_send.execute(args)
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.
@ixje No objection to return the value. I didn't do it because I couldn't think of a use case where it would be useful.
Fix 1 word commands (CityOfZion#727)
- update CommandWalletClose
- make CommandWalletClose.execute a classmethod to avoid having to instantiate it - update per @LysanderGG's comments
- update per @LysanderGG's comments
- return values for testing
- refactor tests
- update returns
- update to support returned data
- remove redundant imports
- return values from `create` and `open`
- update for `make lint`
- add tests for `wallet open` and `wallet close`
- update bad tests
- improve tests
- remove unnecessary logic
@LysanderGG I have implemented the ability to return data which is very useful for testing. see #726 (comment) |
@jseagrave21 Thank you!
Yes I will do it. |
- update close_wallet implementation
- update close_wallet implementation
- update close_wallet implementation
@LysanderGG @ixje Okay, this PR is ready for a [final] review 😉 |
if len(arguments) < 3: | ||
print("Not enough arguments") | ||
return False | ||
return |
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.
Because construct_send_basic
can return [contract_tx, scripthash_from, fee, owners, user_tx_attributes]
it should return None
or False
in early returns.
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.
@LysanderGG
@ixje has explained to me that it is undesirable to have a function return both a boolean and say a function. Instead if you just leave return
blank, it returns none, which will also be interpreted as False, so all my tests pass.
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.
see #716 (comment)
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.
I agree for boolean
and something else (I suggested False
because it was this way before).
I think it should return None
explicitly then.
When I see return
(nothing) I assume that the function doesn't return anything. It can be misleading imo.
@ixje any thoughts?
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.
I'm indifferent when it comes to return
or return None
. I guess I'm used to the idea that return
always returns None
under the hood, so to speak. Might as well make it explicit if that clarifies it for all future readers. I'll probably need to slapping on the fingers to remind me of doing that though ;)
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.
The add a few more words regarding return values; at some point I expect to start applying gradual typing. We've had past cases where functions were returning None
, bool
or a tuple
. That's just not workable.
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.
Thanks for the answer, I won't make this as a blocker for this PR, so @jseagrave21 as you want 😄
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.
I would like to leave it this way so the format is consistent with #716. Consistency is what matters most to me so people will be able to follow our example throughout the code.
if len(arguments) is 0: | ||
print("Not enough arguments") | ||
return False | ||
return |
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 return something here too (and other early returns).
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.
|
||
if not os.path.exists(path): | ||
print("Wallet file not found") | ||
return |
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 return something here too (and other early returns).
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.
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.
I approve the code, I didn't review the tests.
Thank you very much for your help on this!
Sorry for all the nitpicking 😅
@jseagrave21 don't worry, I'm going to merge in a minute and will then update these return parts as I want to update a couple of descriptions. We learn as we go, and while reviewing and testing your PR I noticed the following below
Nothing you could necessarily do about upfront and no need for you to update this as I already have the code. Just take note of how the commands are labelled as well as how their descriptions look for future commits. |
@LysanderGG no worries. I appreciate a critical look. Keeps us all sharp and in the end improves overall quality. |
@LysanderGG @ixje thank you for your thorough reviews. Great team effort! 🎉 |
* Add the bases for making prompt commands plugin based (#720) * WIP make prompt commands plugin based Signed-off-by: Guillaume George <[email protected]> * Merge ixje:refactor-prompt Signed-off-by: Guillaume George <[email protected]> * Handle help detection in prompt.py Signed-off-by: Guillaume George <[email protected]> * Use CommandBase for subcommands to be able to have N levels of commands. Signed-off-by: Guillaume George <[email protected]> * Move "create wallet" command into "wallet" Signed-off-by: Guillaume George <[email protected]> * Improve CommandBase.register_sub_command to use the subcommand's CommandDesc.command as an id. (#725) Signed-off-by: Guillaume George <[email protected]> * Fix 1 word commands (#727) * Improve CommandBase.register_sub_command to use the subcommand's CommandDesc.command as an id. Signed-off-by: Guillaume George <[email protected]> * Fix exception when a command was used without arguments (for example "wallet") Signed-off-by: Guillaume George <[email protected]> * Add support for `wallet` `send`, `sendmany`, `sign`, `open`, and `close` (#726) * Prompt cleanup (#730) * Update description and clarify debug logs * Make return's explicit, clarify multi-sig help message * cleanup prompt * remove colour from initial help, sort commands alphabetically, cleanup descriptions * fix linting * process feedback * [refactor-prompt] Prompt fixes (#732) * Improve CommandBase.register_sub_command to use the subcommand's CommandDesc.command as an id. Signed-off-by: Guillaume George <[email protected]> * Fix CommandWalletCreateAddress missing parameter desc Signed-off-by: Guillaume George <[email protected]> * Fix missing words for autocompletion Signed-off-by: Guillaume George <[email protected]> * [refactor-prompt] Add missing tests for wallet create, verbose and create_addr (#733) * Add missing tests for wallet create, verbose and create_addr Signed-off-by: Guillaume George <[email protected]> * fix reviews Signed-off-by: Guillaume George <[email protected]> * [refactor prompt] Add support for search method group (#739) * [refactor prompt] Add support for show method group (pt 1) (#738) * Fix NodeLeader was not reset between test cases. (#742) This would lead to some problems when the blockchain is reset but the NodeLeader instance members are not. Transactions were still considered as known. Some members were not reset in NodeLeader.Setup() Also removed unsued member NodeLeader.MissionsGlobal Signed-off-by: Guillaume George <[email protected]> * Migrate command: wallet rebuild (#747) Signed-off-by: Guillaume George <[email protected]> * remove deprecated migrate command * remove deprecated migrate command (#748) * [refactor prompt] Add support for show method group (pt 2) (#741) * [refactor-prompt] Implement CommandWalletClaimGas (#740) * [refactor-prompt] Add wallet token base + delete (#757) * [refactor-prompt] Migrate command: wallet delete_addr (#752) * Migrate command: wallet delete_addr Signed-off-by: Guillaume George <[email protected]> * UserWallet.DeleteAddress now returns False on error + proper handling of invalid addresses in CommandWalletDeleteAddress Signed-off-by: Guillaume George <[email protected]> * Migrate command: wallet alias (#753) Signed-off-by: Guillaume George <[email protected]> * [refactor-prompt] Add wallet token send (#758) * remove deprecated migrate command * Add wallet token send * Update requirements and use isValidPublicAddress from new neo-python-core version * - fix send token description - process feedback * fix doc string typo * [refactor prompt] Add support for config group pt1 (#759) * add wallet import nep2/wif (#765) * [refactor-prompt] add wallet token history (#763) * Add wallet token history * process feedback * fix broken test after base branch merge * [refactor-prompt] add wallet export commands (#764) * add wallet export commands * Fix export nep2 to ask for passwords to prevent pw leaking to logs * process feedback * [refactor-prompt] add wallet import watchaddr (#766) * [refactor-prompt] add token sendfrom (#761) * [refactor-prompt] add import multisig_addr (#767) * add import multsig address * remove obsolete function * [refactor-prompt] Migrate command: wallet unspent (#760) * migrate command: wallet unspent Signed-off-by: Guillaume George <[email protected]> * wallet unspent - add tests Signed-off-by: Guillaume George <[email protected]> * fix arguments names and missing doc Signed-off-by: Guillaume George <[email protected]> * Handle review: add feedback when there is no asset matching the arguments + use neocore.Utils.isValidPublicAddress Signed-off-by: Guillaume George <[email protected]> * [refactor prompt] Add support for config maxpeers (#762) * add token approve and token allowance (#769) * add config nep8 (#771) * [refactor-prompt] Migrate command: wallet split (#770) * Migrate command wallet split Signed-off-by: Guillaume George <[email protected]> * Fix some comments Signed-off-by: Guillaume George <[email protected]> * Fix command desc + remove print() calls committed by mistake Signed-off-by: Guillaume George <[email protected]> * Add tests for CommandWalletSplit Signed-off-by: Guillaume George <[email protected]> * Review: test_wallet_split use string arguments instead of ints Signed-off-by: Guillaume George <[email protected]> * Handle Reviews - handle negative fees, improve error messages Signed-off-by: Guillaume George <[email protected]> * add token mint (#773) * [refactor prompt] Fix `search asset` and `search contract` (#774) * Update prompt.py - add CommandShow and CommandSearch to prompt * Update prompt.py revert changes * Update Search.py - update `search contract` and `search asset` per #623 (comment) * Update test_search_commands.py - add tests in case no search parameter is provided * add token register (#775) * [refactor-prompt] Migrate command: wallet import token (#772) * test_wallet_commands.py: Move tests of non commands at the end Signed-off-by: Guillaume George <[email protected]> * Add wallet import token Signed-off-by: Guillaume George <[email protected]> * Review: return None implicitly where possible Signed-off-by: Guillaume George <[email protected]> * Add a few tests for SplitUnspentCoin() Signed-off-by: Guillaume George <[email protected]> * CommandWalletImportToken - Handle review: better validation of contract_hash Signed-off-by: Guillaume George <[email protected]> * Add wallet import contract_addr (#777) Signed-off-by: Guillaume George <[email protected]> * split prompt wallet into multiple files (#782) * [refactor-prompt] add support for the sc group including build, build_run, and load_run (#779) * [refactor-prompt] cleanup 2 (#783) * make base command response consistent * fix plurality * check input parameters before closing wallet * streamline missing arguments response streamline accepted boolean options for config * process feedback * [refactor-prompt] add debugstorage command (#784) * add debugstorage command (and fix auto save linting error) * correct comments * [refactor-prompt] add sc deploy (#785) * add sc deploy (previously known as; import contract) * process feedback * [refactor-prompt] add sc invoke (#786) * add sc invoke (previously known as testinvoke) * process feedback * streamline parameter descriptions (#787) * add wallet password checking before exporting (#790) * fix exception in help if command has no params (#792) * [refactor-prompt] enforce pw prompt send (#791) * remove password bypass * remove unused import * [refactor-prompt] update docs (#789) * update global readme * update docs * process feedback * update show contract output * [refactor-prompt] restore theming support (#788) * re-store theming support * fix comment * improve wallet usage help (#794) * clarify insufficient funds error message due to not enough unspent outputs (#793) * fix prompt printer for lists and other possible objects (#795) * Fix send/sendmany default wallet source address for tx (#796) * [refactor-prompt] Improve send & sendmany (third try) (#799) * Update Send.py * Update test_send_command.py * rename test_send_command.py as test_send_commands.py * [refactor-prompt] Fix #800 (#802) * Update prompt.py - add CommandShow and CommandSearch to prompt * Update prompt.py revert changes * Fix #800 - adds support for contracts not requiring params * fix calculation of change value when using alternating asset inputs (#803) * test print fix * oops * test again * update makefile * update changelog to trigger stuck build
What current issue(s) does this address, or what feature is it adding?
wallet
send
,sendmany
,sign
,open
, andclose
How did you solve this problem?
Trial and Error
How did you make sure your solution works?
manual testing. I haven't added coverage yet.
-update-
I added coverage for
send
andsendmany
. Let me know what you think.Are there any special changes in the code that we should be aware of?
No. But please check my implementation to see if I am on the right track.
Please check the following, if applicable:
make lint
?make test
?CHANGELOG.rst
? (if not, please do)