Skip to content
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

rpc: Add dumpcoinstats #19792

Closed
wants to merge 3 commits into from
Closed

rpc: Add dumpcoinstats #19792

wants to merge 3 commits into from

Conversation

fjahr
Copy link
Contributor

@fjahr fjahr commented Aug 24, 2020

Requires #19521 (this PR only adds the last commit).

The rpc dumpcoinstats dumps the content of the coinstats index into a CSV file for auditing purposes.

@DrahtBot
Copy link
Contributor

DrahtBot commented Aug 24, 2020

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Reviews

See the guideline for information on the review process.

Type Reviewers
Concept ACK laanwj, promag
Approach ACK Zero-1729
Stale ACK PierreRochard, w0xlt, Sjors

If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update.

Conflicts

Reviewers, this pull request conflicts with the following ones:

  • #27607 (init: verify blocks data existence only once for all the indexers by furszy)
  • #20892 (tests: Run both descriptor and legacy tests within a single test invocation by achow101)

If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

@fjahr
Copy link
Contributor Author

fjahr commented Aug 25, 2020

Taking this out of draft status since I am interested in conceptual feedback on something like this but of course, #19521 still has a long way to go before this can be seriously considered.

@PierreRochard
Copy link
Contributor

Tested ACK 21c42c2

@laanwj
Copy link
Member

laanwj commented Aug 27, 2020

Concept ACK, I wish we had gotten streaming to work though so that the file can be downloaded (see my experiment in #7759). RPCs that creates a server-local file, although there are already some others, are not that great from a security and usability point of view.

@fjahr
Copy link
Contributor Author

fjahr commented Sep 22, 2020

Rebased on top of the latest changes in #19521

@Sjors
Copy link
Member

Sjors commented May 30, 2022

re-tACK 3b3e3d9

Copy link
Member

@maflcko maflcko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure about the cs_main locking assumptions

src/rpc/blockchain.cpp Outdated Show resolved Hide resolved
src/rpc/blockchain.cpp Outdated Show resolved Hide resolved
NodeContext& node = EnsureAnyNodeContext(request.context);
ChainstateManager& chainman = EnsureChainman(node);
CChainState& active_chainstate = chainman.ActiveChainstate();
active_chainstate.ForceFlushStateToDisk();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pretty sure flushing and getting the cursor will need to happen in the same cs_main scope, otherwise the flush seems best-effort at best?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I would have described it as best effort so I think it can be omitted here as well. And this made me realize that we don't actually need coins_view and blockman, so I adapted this as well.

src/rpc/blockchain.cpp Outdated Show resolved Hide resolved
src/rpc/blockchain.cpp Outdated Show resolved Hide resolved
else:
file = "test.csv"

path = os.path.join(get_datadir_path(self.options.tmpdir, 1), file)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably time to introduce a helper and use that:

diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py
index 7d2db391b6..aa9ff9831f 100755
--- a/test/functional/test_framework/test_node.py
+++ b/test/functional/test_framework/test_node.py
@@ -381,9 +381,13 @@ class TestNode():
     def wait_until_stopped(self, timeout=BITCOIND_PROC_WAIT_TIMEOUT):
         wait_until_helper(self.is_node_stopped, timeout=timeout, timeout_factor=self.timeout_factor)
 
+    @property
+    def datadir_path(self) -> Path:
+        return Path(self.datadir)
+
     @property
     def chain_path(self) -> Path:
-        return Path(self.datadir) / self.chain
+        return self.datadir_path / self.chain
 
     @property
     def debug_log_path(self) -> Path:
Suggested change
path = os.path.join(get_datadir_path(self.options.tmpdir, 1), file)
path = self.nodes[1].datadir_path / file

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the helper but using the / operator would mean file would also need to be a Path object iiuc. So, instead I opted for a slightly different approach that I liked a little better using another helper datadir_file_path. What do you think?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but using the / operator would mean file would also need to be a Path object iiuc

Does it? (It doesn't for me locally)

Copy link
Contributor Author

@fjahr fjahr Jun 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, seems like I misinterpreted the error, actually the next line fails. And I am now also seeing it fail with the Path object but I am sure it previously passed at least twice with it. Very strange. Maybe a python version or platform issue, need to look deeper into this.

2022-06-11T16:28:24.998000Z TestFramework (INFO): Test dumpcoinstats RPC
2022-06-11T16:28:24.998000Z TestFramework (ERROR): Unexpected exception caught during testing
Traceback (most recent call last):
  File "/Users/FJ/projects/clones/bitcoin/test/functional/test_framework/test_framework.py", line 133, in main
    self.run_test()
  File "/Users/FJ/projects/clones/bitcoin/test/functional/feature_coinstatsindex.py", line 58, in run_test
    self._test_dumpcoinstats_rpc()
  File "/Users/FJ/projects/clones/bitcoin/test/functional/feature_coinstatsindex.py", line 319, in _test_dumpcoinstats_rpc
    self.nodes[1].dumpcoinstats(path, cumulative)
  File "/Users/FJ/projects/clones/bitcoin/test/functional/test_framework/coverage.py", line 49, in __call__
    return_val = self.auth_service_proxy_instance.__call__(*args, **kwargs)
  File "/Users/FJ/projects/clones/bitcoin/test/functional/test_framework/authproxy.py", line 141, in __call__
    postdata = json.dumps(self.get_request(*args, **argsn), default=EncodeDecimal, ensure_ascii=self.ensure_ascii)
  File "/Users/FJ/projects/clones/bitcoin/test/functional/test_framework/authproxy.py", line 131, in get_request
    json.dumps(args or argsn, default=EncodeDecimal, ensure_ascii=self.ensure_ascii),
  File "/opt/homebrew/Cellar/python@3.9/3.9.12/Frameworks/Python.framework/Versions/3.9/lib/python3.9/json/__init__.py", line 234, in dumps
    return cls(
  File "/opt/homebrew/Cellar/python@3.9/3.9.12/Frameworks/Python.framework/Versions/3.9/lib/python3.9/json/encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/opt/homebrew/Cellar/python@3.9/3.9.12/Frameworks/Python.framework/Versions/3.9/lib/python3.9/json/encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
  File "/Users/FJ/projects/clones/bitcoin/test/functional/test_framework/authproxy.py", line 66, in EncodeDecimal
    raise TypeError(repr(o) + " is not JSON serializable")
TypeError: PosixPath('/var/folders/9z/n7rz_6cj3bq__11k5kcrsvvm0000gn/T/bitcoin_func_test_ru27w0qw/node1/ctest.csv') is not JSON serializable

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could do str(path) before passing it as json?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that works too and I just pushed a version with that. But I find it a little less elegant overall.

@fjahr fjahr force-pushed the dumpcoinstats branch 2 times, most recently from c8b5d0a to 42763a2 Compare June 11, 2022 18:50
Copy link
Member

@aureleoules aureleoules left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the index has not fully been synced yet, the error thrown would be:

Failed to get coins stats at height X. You may have to remove an incomplete dump file before running this command again.

It's not very clear that the index has not finished syncing.
Also, the csv file would be created before this error is thrown, so the file would have to be removed manually.

I would suggest checking if the index is synced before dumping and create the file only if the index is ready+enabled, with something like this:

Diff
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 74877d7da..7bb6e2927 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -1039,16 +1039,21 @@ static RPCHelpMan dumpcoinstats()
                 throw JSONRPCError(RPC_INVALID_PARAMETER, filepath.u8string() + " already exists. If you are sure this is what you want, move it out of the way first");
             }
 
+            if (!g_coin_stats_index) {
+                throw JSONRPCError(RPC_MISC_ERROR, "Coinstats index is not enabled");
+            }
+
+            const auto summary{g_coin_stats_index->GetSummary()};
+            if (!summary.synced) {
+                throw JSONRPCError(RPC_MISC_ERROR, strprintf("coinstatsindex is not synced. Current best block height: %d", summary.best_block_height));
+            }
+
             std::ofstream file;
             file.open(filepath);
             if (!file.is_open()) {
                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open dump file");
             }
 
-            if (!g_coin_stats_index) {
-                throw JSONRPCError(RPC_MISC_ERROR, "Coinstats index is not enabled");
-            }
-
             const bool cumulative{request.params[1].isNull() ? false : request.params[1].get_bool()};
 
             file << strprintf("height,"

src/rpc/blockchain.cpp Outdated Show resolved Hide resolved
@fjahr
Copy link
Contributor Author

fjahr commented Dec 22, 2022

Addressed comments from @aureleoules , thanks for the review!

Further note: I can't change the status back it seems, but please treat this as a draft for now. This PR will need to be updated and rebased soon when I have resolved the overflow issue noted in #26362.

EDIT: Rebased as well since there was a silent merge conflict.

@fjahr
Copy link
Contributor Author

fjahr commented Dec 22, 2022

Thanks @fanquake , lightning speed :)

fjahr added 3 commits May 3, 2023 14:04
This RPC dumps the full content of the coinstats index together with some other statistics into a CSV file.
@DrahtBot
Copy link
Contributor

🐙 This pull request conflicts with the target branch and needs rebase.

@DrahtBot
Copy link
Contributor

There hasn't been much activity lately and the patch still needs rebase. What is the status here?

  • Is it still relevant? ➡️ Please solve the conflicts to make it ready for review and to ensure the CI passes.
  • Is it no longer relevant? ➡️ Please close.
  • Did the author lose interest or time to work on this? ➡️ Please close it and mark it 'Up for grabs' with the label, so that it can be picked up in the future.

@fjahr
Copy link
Contributor Author

fjahr commented Aug 15, 2023

There doesn't seem to be much interest in this feature currently. If someone needs it, feel free to ping me here and I will reorg/rebase for you.

@fjahr fjahr closed this Aug 15, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet