Compare commits
510 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
333685dcfe | ||
|
119815f2da | ||
|
8c3a8a1e0f | ||
|
f20371d0a7 | ||
|
2b7ef2cf18 | ||
|
717b36bddd | ||
|
ec9f9bd5d8 | ||
|
a645b9481d | ||
|
6812828ba8 | ||
|
fa70b0f2ff | ||
|
ffbe558a2a | ||
|
8d915aa5b0 | ||
|
eb0f51e487 | ||
|
b410c57f66 | ||
|
fe0297983f | ||
|
f1265b544c | ||
|
3318772bfe | ||
|
141d6d1fc9 | ||
|
0cd6838c23 | ||
|
ab235b8160 | ||
|
51e8872804 | ||
|
5dbec42394 | ||
|
c48298128d | ||
|
db3f154b3f | ||
|
b0e5da40a9 | ||
|
0c2433d796 | ||
|
de03a5092d | ||
|
fd39a09eae | ||
|
0ad7b64961 | ||
|
c9d6fde7cf | ||
|
4462eabd8c | ||
|
e675ef85ce | ||
|
1f693c5925 | ||
|
fc20597cbc | ||
|
0aab403cbc | ||
|
b0523dc236 | ||
|
02d36d0be0 | ||
|
b1e8e8a966 | ||
|
e12cb457fb | ||
|
29ac8f5164 | ||
|
c6818f8faf | ||
|
965e6dfc9a | ||
|
41eab22117 | ||
|
ea2daf0cfa | ||
|
5a61827702 | ||
|
a997c723b5 | ||
|
8b026ba829 | ||
|
05f2b64a6a | ||
|
e341a0b0f2 | ||
|
51a48ae507 | ||
|
b34895db37 | ||
|
3e6398caec | ||
|
b9555116ec | ||
|
81a4769de7 | ||
|
9ee741e021 | ||
|
74c228a9d4 | ||
|
320140fe8e | ||
|
dfcd0c41ec | ||
|
d217ea2afc | ||
|
553209f64c | ||
|
4fcf19e414 | ||
|
e57e632870 | ||
|
20678cf5ef | ||
|
0a05bbca2f | ||
|
ab7dff16a2 | ||
|
5e16e80993 | ||
|
a388b5a356 | ||
|
ef776c0a0e | ||
|
a899d75d2d | ||
|
27733bb4d7 | ||
|
0b9c87b6ec | ||
|
df1e62f23f | ||
|
f697a86d1e | ||
|
64c76c2f4b | ||
|
290d514051 | ||
|
958c43f337 | ||
|
4513128c75 | ||
|
d01968ed21 | ||
|
f9ac24d1f2 | ||
|
fe5a09b50a | ||
|
f59c70a836 | ||
|
74bfb00959 | ||
|
4296bfc728 | ||
|
ccec111178 | ||
|
3a8c6f33a3 | ||
|
06067dd823 | ||
|
9f58a0383c | ||
|
428cacff88 | ||
|
6a4f89b193 | ||
|
65ad72cd64 | ||
|
0ddf684376 | ||
|
1376c325b6 | ||
|
e29a49f107 | ||
|
4e7c096177 | ||
|
b18fa8deac | ||
|
bba4f3006f | ||
|
802a2cc985 | ||
|
ad5ef9cc48 | ||
|
cf1c7c8c00 | ||
|
a28fb586b0 | ||
|
5737ea448e | ||
|
e54a537015 | ||
|
39eae50024 | ||
|
736e5c3ec7 | ||
|
f8e310d99d | ||
|
fd7bcfdb4d | ||
|
e553c8bb45 | ||
|
1c5f8f51ee | ||
|
5084871e27 | ||
|
184a56aae7 | ||
|
7d66cba7f4 | ||
|
8f615278d2 | ||
|
884d68ddcf | ||
|
b095a52027 | ||
|
1f5861e107 | ||
|
b90b46fee1 | ||
|
bff820d549 | ||
|
5ad0ccdfe1 | ||
|
d8c7d06737 | ||
|
422bb3c526 | ||
|
048a2b982c | ||
|
76f0557462 | ||
|
6ebb933302 | ||
|
15a49d7508 | ||
|
a86a781fd5 | ||
|
57d8d0ab6e | ||
|
63fe350900 | ||
|
b384ce9e03 | ||
|
d81d4ad8a1 | ||
|
9ed1d2337b | ||
|
14aaae3485 | ||
|
caac786a38 | ||
|
218a76ed1b | ||
|
964f05afa8 | ||
|
a0e2f49263 | ||
|
25078d46ba | ||
|
840ea326db | ||
|
b9fc31ec95 | ||
|
9481ee79a8 | ||
|
dddd0b76f1 | ||
|
7674a5fea8 | ||
|
78be777b65 | ||
|
9b5c10a6aa | ||
|
8714c14549 | ||
|
1982a7a8e3 | ||
|
c2806aa2f9 | ||
|
e6521ef44c | ||
|
03ab8fac29 | ||
|
644304d171 | ||
|
782ed192b6 | ||
|
0da2f73eb4 | ||
|
a3fdfea674 | ||
|
43121a56eb | ||
|
2c0b4f3b4f | ||
|
db30316bb3 | ||
|
73e4d9d623 | ||
|
46b864dcb0 | ||
|
4f2e60fea4 | ||
|
7ce9beacb6 | ||
|
9dab79274b | ||
|
df8b07ddbd | ||
|
762423c9a9 | ||
|
689aa4d44f | ||
|
cff1496e94 | ||
|
d1c51950f3 | ||
|
774a12e7b9 | ||
|
85e8926d81 | ||
|
a2be9c647f | ||
|
744006fe78 | ||
|
edf59cccd8 | ||
|
9c72bf871f | ||
|
033c87e3f1 | ||
|
d35d853e57 | ||
|
03317f6bf7 | ||
|
4f0e928a0a | ||
|
8600d5188d | ||
|
8cd7716ee3 | ||
|
b13385fba6 | ||
|
9f82208c29 | ||
|
596ede864b | ||
|
e4bd382472 | ||
|
a70aa28832 | ||
|
9a63cf51b5 | ||
|
b31ec0579c | ||
|
ad31768dd9 | ||
|
079ea91d6f | ||
|
48d08f2010 | ||
|
b34ba0fc4e | ||
|
41b99b96c0 | ||
|
fea6e4d39d | ||
|
fced68c3f4 | ||
|
7f006d810c | ||
|
cab1b102e6 | ||
|
448887a469 | ||
|
bded162ed8 | ||
|
765dd1b775 | ||
|
b74fbdf7eb | ||
|
fb0f0adb16 | ||
|
2a3c4d87ce | ||
|
eaa6e04e83 | ||
|
925973ee60 | ||
|
2c55319e41 | ||
|
f22a5efde5 | ||
|
add5c5b29f | ||
|
1b53f8b33d | ||
|
34591d2f2f | ||
|
bc1b95d6d0 | ||
|
90d586a4f8 | ||
|
efcb5cd9f0 | ||
|
ffa0ee69ca | ||
|
a983430ddb | ||
|
bd94250fca | ||
|
db5251a524 | ||
|
efb665071c | ||
|
e69ee1ec64 | ||
|
307686eeba | ||
|
de1e2f9c0c | ||
|
01f93003d3 | ||
|
75219afc91 | ||
|
71526923a6 | ||
|
29af9d1a36 | ||
|
46311181dc | ||
|
17de653ce0 | ||
|
387ecdf70e | ||
|
fbe5a89e74 | ||
|
afbdcf3068 | ||
|
2d1b995006 | ||
|
d9d3a95a72 | ||
|
ea990fd259 | ||
|
4f30f9c8cf | ||
|
d13694d839 | ||
|
700c8c1ec1 | ||
|
33ace54b0f | ||
|
5d2f450b89 | ||
|
55b0e9e9c7 | ||
|
6d1bea7fb4 | ||
|
d19ed8816e | ||
|
af7f48a2fd | ||
|
0965389f41 | ||
|
24c60cf3db | ||
|
c8f4bfca90 | ||
|
4a6b65ce53 | ||
|
836ed842d6 | ||
|
966d0f72bb | ||
|
a07e90516b | ||
|
bd2e09d55a | ||
|
655577f9fe | ||
|
3781ad259b | ||
|
5ad5f8b458 | ||
|
5b322a995f | ||
|
63d9f32bb4 | ||
|
a550d82202 | ||
|
4cf69365b2 | ||
|
873b4ee830 | ||
|
672d9c9f62 | ||
|
4bd29c1b32 | ||
|
72c082f55a | ||
|
d712a908c2 | ||
|
e3ca1a81b4 | ||
|
16bce553e4 | ||
|
bc3aa53e02 | ||
|
6a698af235 | ||
|
7ec38bd71c | ||
|
8e3882287a | ||
|
0c4074049b | ||
|
250d2ba74a | ||
|
b96e0e3d27 | ||
|
99b513d905 | ||
|
e85c792f70 | ||
|
b65a764593 | ||
|
a514b0e77b | ||
|
179dd6ee59 | ||
|
21ba2bad24 | ||
|
64b6372f9c | ||
|
495ea7cd2f | ||
|
bb12d65102 | ||
|
72365bb9d2 | ||
|
c44f6981b1 | ||
|
0213016999 | ||
|
4e9e05f311 | ||
|
7212bb12ea | ||
|
9ff2378948 | ||
|
ec4938a9f3 | ||
|
41b45ca281 | ||
|
838aaee144 | ||
|
c0e44b624e | ||
|
41ca59ea0e | ||
|
a76e175fd0 | ||
|
35a1ab981c | ||
|
0f3a555af5 | ||
|
5366a3c887 | ||
|
486b657fca | ||
|
e545bdcb51 | ||
|
65e4aac306 | ||
|
339e72d8d2 | ||
|
0f3208dece | ||
|
a85a2839e4 | ||
|
4fc9f12d7b | ||
|
8af90c9c08 | ||
|
7db0464d1b | ||
|
bc774e3ea6 | ||
|
64af712723 | ||
|
ea2611f3a9 | ||
|
a26e1f62bb | ||
|
54b87b34c3 | ||
|
12327c8683 | ||
|
86554c4945 | ||
|
95ed3641c6 | ||
|
83c775cee8 | ||
|
9fbbb7b044 | ||
|
7656034bd4 | ||
|
3ede265ff9 | ||
|
a20e954a16 | ||
|
1f69b125ce | ||
|
0196c83846 | ||
|
37175d0cdf | ||
|
a6e73acfa4 | ||
|
f00c504555 | ||
|
19eb73d645 | ||
|
d35dc79ee7 | ||
|
2316846c53 | ||
|
c77fe54629 | ||
|
953c40a9e3 | ||
|
c10f14d60b | ||
|
c3c3872f8d | ||
|
c539526f1e | ||
|
8ea4c1c2c0 | ||
|
557fee8183 | ||
|
1957e960ac | ||
|
11ff80c64b | ||
|
7267257073 | ||
|
f107b9b423 | ||
|
1354a0c1a3 | ||
|
52ee9155b5 | ||
|
65a1884c7b | ||
|
c1a9c826f3 | ||
|
d9d8ec480a | ||
|
b5c7ad3a9b | ||
|
771ff65fb4 | ||
|
a5bf59b92a | ||
|
8dc019ae98 | ||
|
61dcab8c07 | ||
|
640bf7015f | ||
|
db1f57162a | ||
|
bbddffa805 | ||
|
61cf432477 | ||
|
9396618c12 | ||
|
398f12dcc5 | ||
|
796624adf9 | ||
|
f6e266eff0 | ||
|
ed237af4d8 | ||
|
415c80c204 | ||
|
e45f1df5dd | ||
|
d26a809f1f | ||
|
d1fdc96969 | ||
|
a5cad340ed | ||
|
2341394e8b | ||
|
180224114a | ||
|
58312655b4 | ||
|
f3f86f43ee | ||
|
aac38516da | ||
|
cd139b8185 | ||
|
6a74bc1297 | ||
|
e9a2dd0bc1 | ||
|
feed960ef3 | ||
|
ae8acada8c | ||
|
357a341db5 | ||
|
d0f715cb23 | ||
|
0fc0378347 | ||
|
aa3bdd3730 | ||
|
962aed0961 | ||
|
bd76810623 | ||
|
58fe45f3e5 | ||
|
01a9360dbe | ||
|
f44d9d770a | ||
|
79d9d28e7d | ||
|
d273d1acb2 | ||
|
991f188f23 | ||
|
8f02fdcc11 | ||
|
3e78850331 | ||
|
f29a741582 | ||
|
3e6052faca | ||
|
0b0710d522 | ||
|
2f3fced8a8 | ||
|
a5832366a7 | ||
|
f26ff6d6b2 | ||
|
57f149e415 | ||
|
8ece3847f9 | ||
|
0d23ad00b1 | ||
|
d9684f99c3 | ||
|
6ea9c249d7 | ||
|
1e02069f86 | ||
|
b179ed0b90 | ||
|
eb65ff750e | ||
|
663dc9959f | ||
|
53ed6a2298 | ||
|
47962f3e80 | ||
|
d3a16e4e13 | ||
|
250f5a8196 | ||
|
83a17acc17 | ||
|
ed34b930e5 | ||
|
95816f7db9 | ||
|
e652c27142 | ||
|
0811cb2966 | ||
|
311b419f8a | ||
|
acb992c3be | ||
|
61aca235a3 | ||
|
bad0709ff1 | ||
|
2a649e990d | ||
|
1a25889f72 | ||
|
e15dca6961 | ||
|
bb12f48014 | ||
|
c6416fca6e | ||
|
2f5d60bef7 | ||
|
ef1a9df507 | ||
|
d2611f54a0 | ||
|
6117f8d64e | ||
|
67d9faaefc | ||
|
aaa551ca7c | ||
|
85df8cb4c5 | ||
|
65f189d932 | ||
|
99001f7f2e | ||
|
39eeb0142e | ||
|
d5d1a344c3 | ||
|
62e3c084d3 | ||
|
3027ceb53a | ||
|
4e604e1211 | ||
|
6749bfd1d2 | ||
|
d05b39c4f6 | ||
|
c8e1fbd568 | ||
|
ad36ddedf1 | ||
|
08bece7651 | ||
|
f162c6d1d0 | ||
|
f3904b5765 | ||
|
67bf7515a7 | ||
|
0dcbc6d4d1 | ||
|
79a2ccabb4 | ||
|
f5e583ef0d | ||
|
132550cd7a | ||
|
08a789323f | ||
|
2d9781b101 | ||
|
6540d3c63e | ||
|
a227b813d8 | ||
|
2b4e0abb43 | ||
|
cdf6ff7907 | ||
|
6775e01747 | ||
|
4be9d5030d | ||
|
a9f914da8e | ||
|
096375584b | ||
|
d3ab1ec9cf | ||
|
e41d9c87c5 | ||
|
e938925b95 | ||
|
6c03e6c4b5 | ||
|
abce60efdf | ||
|
b36510a565 | ||
|
a8220ae653 | ||
|
2c642d4639 | ||
|
04eb35e679 | ||
|
8738241567 | ||
|
0ef9185c9e | ||
|
e41004f185 | ||
|
41cad9ccd5 | ||
|
d9ae092637 | ||
|
9015e47cc5 | ||
|
15b92e9c8d | ||
|
c72bd900cd | ||
|
ecb75ccdcf | ||
|
cf22e7a273 | ||
|
4f7bfbdbe9 | ||
|
011e325359 | ||
|
ba05852475 | ||
|
8ee656edde | ||
|
311d9a56c4 | ||
|
b9f46fd904 | ||
|
39f2d346b8 | ||
|
4a27bfa2fe | ||
|
69e53ec92a | ||
|
b8ac76066c | ||
|
1a1d7744bd | ||
|
61af485732 | ||
|
6a60d7bf8e | ||
|
53e917b54f | ||
|
4d49c99ac9 | ||
|
83597a5ce1 | ||
|
1589a41178 | ||
|
23a381b995 | ||
|
eb7ac42b2e | ||
|
88cf5e79f5 | ||
|
520453e1f3 | ||
|
27815555a1 | ||
|
3e483314b6 | ||
|
8a67504578 | ||
|
a1b238280b | ||
|
f9e07f575e | ||
|
c8bad57455 | ||
|
71654c0457 | ||
|
f9d6fb48a4 | ||
|
fa9aa0a1d7 | ||
|
9758ebfc99 | ||
|
8be23a2bb2 | ||
|
4ff9a6910d | ||
|
fd192e3641 | ||
|
a8de467ef8 | ||
|
1a186beb5c | ||
|
66a21ed65e | ||
|
1a42a40492 | ||
|
5841e4d665 | ||
|
6542a04521 | ||
|
5c27009758 | ||
|
888f3522d8 |
1
.buildkite/env/secrets.ejson
vendored
1
.buildkite/env/secrets.ejson
vendored
@@ -1,6 +1,5 @@
|
||||
{
|
||||
"_public_key": "ae29f4f7ad2fc92de70d470e411c8426d5d48db8817c9e3dae574b122192335f",
|
||||
"_comment": "These credentials are encrypted and pose no risk",
|
||||
"environment": {
|
||||
"CODECOV_TOKEN": "EJ[1:Z7OneT3RdJJ0DipCHQ7rC84snQ+FPbgHwZADQiz54wk=:3K68mE38LJ2RB98VWmjuNLFBNn1XTGR4:cR4r05/TOZQKmEZp1v4CSgUJtC6QJiOaL85QjXW0qZ061fMnsBA8AtAPMDoDq4WCGOZM1A==]"
|
||||
}
|
||||
|
Binary file not shown.
@@ -1,4 +0,0 @@
|
||||
Signature: 8a477f597d28d172789f06886806bc55
|
||||
# This file is a cache directory tag created by fontconfig.
|
||||
# For information about cache directory tags, see:
|
||||
# http://www.brynosaurus.com/cachedir/
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
46
.github/stale.yml
vendored
46
.github/stale.yml
vendored
@@ -1,3 +1,11 @@
|
||||
only: pulls
|
||||
|
||||
# Number of days of inactivity before a pull request becomes stale
|
||||
daysUntilStale: 7
|
||||
|
||||
# Number of days of inactivity before a stale pull request is closed
|
||||
daysUntilClose: 7
|
||||
|
||||
# Issues with these labels will never be considered stale
|
||||
exemptLabels:
|
||||
- security
|
||||
@@ -6,34 +14,12 @@ exemptLabels:
|
||||
# Label to use when marking a pull request as stale
|
||||
staleLabel: stale
|
||||
|
||||
pulls:
|
||||
# Number of days of inactivity before a pull request becomes stale
|
||||
daysUntilStale: 7
|
||||
# Comment to post when marking a pull request as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
This pull request has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed if no further activity occurs.
|
||||
|
||||
# Number of days of inactivity before a stale pull request is closed
|
||||
daysUntilClose: 7
|
||||
# Comment to post when marking a pull request as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
This pull request has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed if no further activity occurs.
|
||||
|
||||
# Comment to post when closing a stale pull request. Set to `false` to disable
|
||||
closeComment: >
|
||||
This stale pull request has been automatically closed.
|
||||
Thank you for your contributions.
|
||||
|
||||
issues:
|
||||
# Number of days of inactivity before a issue becomes stale
|
||||
daysUntilStale: 365
|
||||
|
||||
# Number of days of inactivity before a stale issue is closed
|
||||
daysUntilClose: 7
|
||||
# Comment to post when marking a issue as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
This issue has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed if no further activity occurs.
|
||||
|
||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||
closeComment: >
|
||||
This stale issue has been automatically closed.
|
||||
Thank you for your contributions.
|
||||
# Comment to post when closing a stale pull request. Set to `false` to disable
|
||||
closeComment: >
|
||||
This stale pull request has been automatically closed.
|
||||
Thank you for your contributions.
|
||||
|
16
.mergify.yml
16
.mergify.yml
@@ -50,6 +50,14 @@ pull_request_rules:
|
||||
label:
|
||||
add:
|
||||
- automerge
|
||||
- name: v1.1 backport
|
||||
conditions:
|
||||
- label=v1.1
|
||||
actions:
|
||||
backport:
|
||||
ignore_conflicts: true
|
||||
branches:
|
||||
- v1.1
|
||||
- name: v1.2 backport
|
||||
conditions:
|
||||
- label=v1.2
|
||||
@@ -66,11 +74,3 @@ pull_request_rules:
|
||||
ignore_conflicts: true
|
||||
branches:
|
||||
- v1.3
|
||||
- name: v1.4 backport
|
||||
conditions:
|
||||
- label=v1.4
|
||||
actions:
|
||||
backport:
|
||||
ignore_conflicts: true
|
||||
branches:
|
||||
- v1.4
|
||||
|
@@ -34,8 +34,6 @@ jobs:
|
||||
- stable
|
||||
install:
|
||||
- source ci/rust-version.sh
|
||||
- PATH="/usr/local/opt/coreutils/libexec/gnubin:$PATH"
|
||||
- readlink -f .
|
||||
script:
|
||||
- source ci/env.sh
|
||||
- ci/publish-tarball.sh
|
||||
|
@@ -232,7 +232,7 @@ confused with 3-letter acronyms.
|
||||
Solana's architecture is described by docs generated from markdown files in
|
||||
the `docs/src/` directory, maintained by an *editor* (currently @garious). To
|
||||
add a design proposal, you'll need to include it in the
|
||||
[Accepted Design Proposals](https://docs.solana.com/proposals/accepted-design-proposals)
|
||||
[Accepted Design Proposals](https://docs.solana.com/proposals)
|
||||
section of the Solana docs. Here's the full process:
|
||||
|
||||
1. Propose a design by creating a PR that adds a markdown document to the
|
||||
|
1133
Cargo.lock
generated
1133
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -16,7 +16,6 @@ members = [
|
||||
"dos",
|
||||
"download-utils",
|
||||
"faucet",
|
||||
"frozen-abi",
|
||||
"perf",
|
||||
"validator",
|
||||
"genesis",
|
||||
@@ -31,14 +30,12 @@ members = [
|
||||
"merkle-tree",
|
||||
"stake-o-matic",
|
||||
"storage-bigtable",
|
||||
"storage-proto",
|
||||
"streamer",
|
||||
"measure",
|
||||
"metrics",
|
||||
"net-shaper",
|
||||
"notifier",
|
||||
"poh-bench",
|
||||
"program-test",
|
||||
"programs/secp256k1",
|
||||
"programs/bpf_loader",
|
||||
"programs/budget",
|
||||
@@ -54,8 +51,6 @@ members = [
|
||||
"ramp-tps",
|
||||
"runtime",
|
||||
"sdk",
|
||||
"sdk/cargo-build-bpf",
|
||||
"sdk/cargo-test-bpf",
|
||||
"scripts",
|
||||
"stake-accounts",
|
||||
"stake-monitor",
|
||||
|
@@ -19,7 +19,7 @@ $ source $HOME/.cargo/env
|
||||
$ rustup component add rustfmt
|
||||
```
|
||||
|
||||
Please sure you are always using the latest stable rust version by running:
|
||||
If your rustc version is lower than 1.39.0, please update it:
|
||||
|
||||
```bash
|
||||
$ rustup update
|
||||
@@ -59,7 +59,7 @@ $ cargo test
|
||||
```
|
||||
|
||||
### Starting a local testnet
|
||||
Start your own testnet locally, instructions are in the [online docs](https://docs.solana.com/cluster/bench-tps).
|
||||
Start your own testnet locally, instructions are in the [online docs](https://docs.solana.com/bench-tps).
|
||||
|
||||
### Accessing the remote development cluster
|
||||
* `devnet` - stable public cluster for development accessible via
|
||||
|
17
RELEASE.md
17
RELEASE.md
@@ -107,15 +107,11 @@ Alternatively use the Github UI.
|
||||
1. If the Cargo.toml version field is **0.12.3**, then the release tag must be **v0.12.3**
|
||||
1. Make sure the Target Branch field matches the branch you want to make a release on.
|
||||
1. If you want to release v0.12.0, the target branch must be v0.12
|
||||
1. Fill the release notes.
|
||||
1. If this is the first release on the branch (e.g. v0.13.**0**), paste in [this
|
||||
template](https://raw.githubusercontent.com/solana-labs/solana/master/.github/RELEASE_TEMPLATE.md). Engineering Lead can provide summary contents for release notes if needed.
|
||||
1. If this is a patch release, review all the commits since the previous release on this branch and add details as needed.
|
||||
1. If this is the first release on the branch (e.g. v0.13.**0**), paste in [this
|
||||
template](https://raw.githubusercontent.com/solana-labs/solana/master/.github/RELEASE_TEMPLATE.md). Engineering Lead can provide summary contents for release notes if needed. If this is a patch release, review all the commits since the previous release on this branch and add details as needed.
|
||||
1. Click "Save Draft", then confirm the release notes look good and the tag name and branch are correct.
|
||||
1. Ensure all desired commits (usually backports) are landed on the branch by now.
|
||||
1. Ensure the release is marked **"This is a pre-release"**. This flag will need to be be removed manually after confirming the the Linux binary artifacts appear at a later step.
|
||||
1. Go back into edit the release and click "Publish release" while being marked as a pre-release.
|
||||
1. Confirm there is new git tag with intended version number at the intended revision after running `git fetch` locally.
|
||||
1. Ensure the release is marked **"This is a pre-release"**. This flag will then need to be be removed once the the Linux binary artifacts appear later.
|
||||
1. Go back into edit the release and click "Publish release" when ready.
|
||||
|
||||
|
||||
### Update release branch with the next patch version
|
||||
@@ -135,8 +131,7 @@ Alternatively use the Github UI.
|
||||
1. Open a PR against origin/vX.Y and then merge the PR after passing CI.
|
||||
|
||||
### Prepare for the next release
|
||||
1. Go to [GitHub Releases](https://github.com/solana-labs/solana/releases) and create a new draft release for `X.Y.Z+1` with empty release notes. This allows people to incrementally add new release notes until it's time for the next release
|
||||
1. Also, point the branch field to the same branch and mark the relese as **"This is a pre-release"**.
|
||||
1. Go to [GitHub Releases](https://github.com/solana-labs/solana/releases) and create a new draft release for `X.Y.Z+1` with empty release nodes. This allows people to incrementally add new release notes until it's time for the next release
|
||||
1. Go to the [Github Milestones](https://github.com/solana-labs/solana/milestones). Create a new milestone for the `X.Y.Z+1`, move over
|
||||
unresolved issues still in the `X.Y.Z` milestone, then close the `X.Y.Z` milestone.
|
||||
|
||||
@@ -152,5 +147,5 @@ appearing. To check for progress:
|
||||
[Crates.io](https://crates.io/crates/solana) should have an updated Solana version. This can take 2-3 hours, and sometimes fails in the `solana-secondary` job.
|
||||
If this happens and the error is non-fatal, click "Retry" on the "publish crate" job
|
||||
|
||||
### Update software on devnet.solana.com/testnet.solana.com/mainnet-beta.solana.com
|
||||
### Update software on devnet.solana.com/testnet.solama.com/mainnet-beta.solana.com
|
||||
See the documentation at https://github.com/solana-labs/cluster-ops/
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-account-decoder"
|
||||
version = "1.4.26"
|
||||
version = "1.3.24"
|
||||
description = "Solana account decoder"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -18,13 +18,12 @@ lazy_static = "1.4.0"
|
||||
serde = "1.0.112"
|
||||
serde_derive = "1.0.103"
|
||||
serde_json = "1.0.56"
|
||||
solana-config-program = { path = "../programs/config", version = "1.4.26" }
|
||||
solana-sdk = { path = "../sdk", version = "1.4.26" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "1.4.26" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "1.4.26" }
|
||||
spl-token-v2-0 = { package = "spl-token", version = "=3.0.1", features = ["no-entrypoint"] }
|
||||
solana-config-program = { path = "../programs/config", version = "1.3.24" }
|
||||
solana-sdk = { path = "../sdk", version = "1.3.24" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "1.3.24" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "1.3.24" }
|
||||
spl-token-v2-0 = { package = "spl-token", version = "=2.0.6", features = ["skip-no-mangle"] }
|
||||
thiserror = "1.0"
|
||||
zstd = "0.5.1"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
@@ -12,14 +12,9 @@ pub mod parse_token;
|
||||
pub mod parse_vote;
|
||||
pub mod validator_info;
|
||||
|
||||
use {
|
||||
crate::parse_account_data::{parse_account_data, AccountAdditionalData, ParsedAccount},
|
||||
solana_sdk::{account::Account, clock::Epoch, fee_calculator::FeeCalculator, pubkey::Pubkey},
|
||||
std::{
|
||||
io::{Read, Write},
|
||||
str::FromStr,
|
||||
},
|
||||
};
|
||||
use crate::parse_account_data::{parse_account_data, AccountAdditionalData, ParsedAccount};
|
||||
use solana_sdk::{account::Account, clock::Epoch, fee_calculator::FeeCalculator, pubkey::Pubkey};
|
||||
use std::str::FromStr;
|
||||
|
||||
pub type StringAmount = String;
|
||||
|
||||
@@ -49,8 +44,6 @@ pub enum UiAccountEncoding {
|
||||
Base58,
|
||||
Base64,
|
||||
JsonParsed,
|
||||
#[serde(rename = "base64+zstd")]
|
||||
Base64Zstd,
|
||||
}
|
||||
|
||||
impl UiAccount {
|
||||
@@ -73,19 +66,6 @@ impl UiAccount {
|
||||
base64::encode(slice_data(&account.data, data_slice_config)),
|
||||
encoding,
|
||||
),
|
||||
UiAccountEncoding::Base64Zstd => {
|
||||
let mut encoder = zstd::stream::write::Encoder::new(Vec::new(), 0).unwrap();
|
||||
match encoder
|
||||
.write_all(slice_data(&account.data, data_slice_config))
|
||||
.and_then(|()| encoder.finish())
|
||||
{
|
||||
Ok(zstd_data) => UiAccountData::Binary(base64::encode(zstd_data), encoding),
|
||||
Err(_) => UiAccountData::Binary(
|
||||
base64::encode(slice_data(&account.data, data_slice_config)),
|
||||
UiAccountEncoding::Base64,
|
||||
),
|
||||
}
|
||||
}
|
||||
UiAccountEncoding::JsonParsed => {
|
||||
if let Ok(parsed_data) =
|
||||
parse_account_data(pubkey, &account.owner, &account.data, additional_data)
|
||||
@@ -112,16 +92,6 @@ impl UiAccount {
|
||||
UiAccountData::Binary(blob, encoding) => match encoding {
|
||||
UiAccountEncoding::Base58 => bs58::decode(blob).into_vec().ok(),
|
||||
UiAccountEncoding::Base64 => base64::decode(blob).ok(),
|
||||
UiAccountEncoding::Base64Zstd => base64::decode(blob)
|
||||
.ok()
|
||||
.map(|zstd_data| {
|
||||
let mut data = vec![];
|
||||
zstd::stream::read::Decoder::new(zstd_data.as_slice())
|
||||
.and_then(|mut reader| reader.read_to_end(&mut data))
|
||||
.map(|_| data)
|
||||
.ok()
|
||||
})
|
||||
.flatten(),
|
||||
UiAccountEncoding::Binary | UiAccountEncoding::JsonParsed => None,
|
||||
},
|
||||
}?;
|
||||
@@ -209,25 +179,4 @@ mod test {
|
||||
});
|
||||
assert_eq!(slice_data(&data, slice_config), &[] as &[u8]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_base64_zstd() {
|
||||
let encoded_account = UiAccount::encode(
|
||||
&Pubkey::default(),
|
||||
Account {
|
||||
data: vec![0; 1024],
|
||||
..Account::default()
|
||||
},
|
||||
UiAccountEncoding::Base64Zstd,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
assert!(matches!(
|
||||
encoded_account.data,
|
||||
UiAccountData::Binary(_, UiAccountEncoding::Base64Zstd)
|
||||
));
|
||||
|
||||
let decoded_account = encoded_account.decode().unwrap();
|
||||
assert_eq!(decoded_account.data, vec![0; 1024]);
|
||||
}
|
||||
}
|
||||
|
@@ -118,7 +118,7 @@ mod test {
|
||||
|
||||
let vote_state = VoteState::default();
|
||||
let mut vote_account_data: Vec<u8> = vec![0; VoteState::size_of()];
|
||||
let versioned = VoteStateVersions::new_current(vote_state);
|
||||
let versioned = VoteStateVersions::Current(Box::new(vote_state));
|
||||
VoteState::serialize(&versioned, &mut vote_account_data).unwrap();
|
||||
let parsed = parse_account_data(
|
||||
&account_pubkey,
|
||||
|
@@ -105,7 +105,6 @@ pub enum SysvarAccountType {
|
||||
pub struct UiClock {
|
||||
pub slot: Slot,
|
||||
pub epoch: Epoch,
|
||||
pub epoch_start_timestamp: UnixTimestamp,
|
||||
pub leader_schedule_epoch: Epoch,
|
||||
pub unix_timestamp: UnixTimestamp,
|
||||
}
|
||||
@@ -115,7 +114,6 @@ impl From<Clock> for UiClock {
|
||||
Self {
|
||||
slot: clock.slot,
|
||||
epoch: clock.epoch,
|
||||
epoch_start_timestamp: clock.epoch_start_timestamp,
|
||||
leader_schedule_epoch: clock.leader_schedule_epoch,
|
||||
unix_timestamp: clock.unix_timestamp,
|
||||
}
|
||||
@@ -214,14 +212,15 @@ pub struct UiStakeHistoryEntry {
|
||||
mod test {
|
||||
use super::*;
|
||||
use solana_sdk::{
|
||||
account::create_account, fee_calculator::FeeCalculator, hash::Hash,
|
||||
sysvar::recent_blockhashes::IterItem,
|
||||
fee_calculator::FeeCalculator,
|
||||
hash::Hash,
|
||||
sysvar::{recent_blockhashes::IterItem, Sysvar},
|
||||
};
|
||||
use std::iter::FromIterator;
|
||||
|
||||
#[test]
|
||||
fn test_parse_sysvars() {
|
||||
let clock_sysvar = create_account(&Clock::default(), 1);
|
||||
let clock_sysvar = Clock::default().create_account(1);
|
||||
assert_eq!(
|
||||
parse_sysvar(&clock_sysvar.data, &sysvar::clock::id()).unwrap(),
|
||||
SysvarAccountType::Clock(UiClock::default()),
|
||||
@@ -234,13 +233,13 @@ mod test {
|
||||
first_normal_epoch: 1,
|
||||
first_normal_slot: 12,
|
||||
};
|
||||
let epoch_schedule_sysvar = create_account(&epoch_schedule, 1);
|
||||
let epoch_schedule_sysvar = epoch_schedule.create_account(1);
|
||||
assert_eq!(
|
||||
parse_sysvar(&epoch_schedule_sysvar.data, &sysvar::epoch_schedule::id()).unwrap(),
|
||||
SysvarAccountType::EpochSchedule(epoch_schedule),
|
||||
);
|
||||
|
||||
let fees_sysvar = create_account(&Fees::default(), 1);
|
||||
let fees_sysvar = Fees::default().create_account(1);
|
||||
assert_eq!(
|
||||
parse_sysvar(&fees_sysvar.data, &sysvar::fees::id()).unwrap(),
|
||||
SysvarAccountType::Fees(UiFees::default()),
|
||||
@@ -252,7 +251,7 @@ mod test {
|
||||
};
|
||||
let recent_blockhashes =
|
||||
RecentBlockhashes::from_iter(vec![IterItem(0, &hash, &fee_calculator)].into_iter());
|
||||
let recent_blockhashes_sysvar = create_account(&recent_blockhashes, 1);
|
||||
let recent_blockhashes_sysvar = recent_blockhashes.create_account(1);
|
||||
assert_eq!(
|
||||
parse_sysvar(
|
||||
&recent_blockhashes_sysvar.data,
|
||||
@@ -270,13 +269,13 @@ mod test {
|
||||
exemption_threshold: 2.0,
|
||||
burn_percent: 5,
|
||||
};
|
||||
let rent_sysvar = create_account(&rent, 1);
|
||||
let rent_sysvar = rent.create_account(1);
|
||||
assert_eq!(
|
||||
parse_sysvar(&rent_sysvar.data, &sysvar::rent::id()).unwrap(),
|
||||
SysvarAccountType::Rent(rent.into()),
|
||||
);
|
||||
|
||||
let rewards_sysvar = create_account(&Rewards::default(), 1);
|
||||
let rewards_sysvar = Rewards::default().create_account(1);
|
||||
assert_eq!(
|
||||
parse_sysvar(&rewards_sysvar.data, &sysvar::rewards::id()).unwrap(),
|
||||
SysvarAccountType::Rewards(UiRewards::default()),
|
||||
@@ -284,7 +283,7 @@ mod test {
|
||||
|
||||
let mut slot_hashes = SlotHashes::default();
|
||||
slot_hashes.add(1, hash);
|
||||
let slot_hashes_sysvar = create_account(&slot_hashes, 1);
|
||||
let slot_hashes_sysvar = slot_hashes.create_account(1);
|
||||
assert_eq!(
|
||||
parse_sysvar(&slot_hashes_sysvar.data, &sysvar::slot_hashes::id()).unwrap(),
|
||||
SysvarAccountType::SlotHashes(vec![UiSlotHashEntry {
|
||||
@@ -295,7 +294,7 @@ mod test {
|
||||
|
||||
let mut slot_history = SlotHistory::default();
|
||||
slot_history.add(42);
|
||||
let slot_history_sysvar = create_account(&slot_history, 1);
|
||||
let slot_history_sysvar = slot_history.create_account(1);
|
||||
assert_eq!(
|
||||
parse_sysvar(&slot_history_sysvar.data, &sysvar::slot_history::id()).unwrap(),
|
||||
SysvarAccountType::SlotHistory(UiSlotHistory {
|
||||
@@ -311,7 +310,7 @@ mod test {
|
||||
deactivating: 3,
|
||||
};
|
||||
stake_history.add(1, stake_history_entry.clone());
|
||||
let stake_history_sysvar = create_account(&stake_history, 1);
|
||||
let stake_history_sysvar = stake_history.create_account(1);
|
||||
assert_eq!(
|
||||
parse_sysvar(&stake_history_sysvar.data, &sysvar::stake_history::id()).unwrap(),
|
||||
SysvarAccountType::StakeHistory(vec![UiStakeHistoryEntry {
|
||||
|
@@ -4,9 +4,7 @@ use crate::{
|
||||
};
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
use spl_token_v2_0::{
|
||||
solana_program::{
|
||||
program_option::COption, program_pack::Pack, pubkey::Pubkey as SplTokenPubkey,
|
||||
},
|
||||
solana_sdk::{program_option::COption, program_pack::Pack, pubkey::Pubkey as SplTokenPubkey},
|
||||
state::{Account, AccountState, Mint, Multisig},
|
||||
};
|
||||
use std::str::FromStr;
|
||||
@@ -23,16 +21,6 @@ pub fn spl_token_v2_0_native_mint() -> Pubkey {
|
||||
Pubkey::from_str(&spl_token_v2_0::native_mint::id().to_string()).unwrap()
|
||||
}
|
||||
|
||||
// A helper function to convert a solana_sdk::pubkey::Pubkey to spl_sdk::pubkey::Pubkey
|
||||
pub fn spl_token_v2_0_pubkey(pubkey: &Pubkey) -> SplTokenPubkey {
|
||||
SplTokenPubkey::from_str(&pubkey.to_string()).unwrap()
|
||||
}
|
||||
|
||||
// A helper function to convert a spl_sdk::pubkey::Pubkey to solana_sdk::pubkey::Pubkey
|
||||
pub fn pubkey_from_spl_token_v2_0(pubkey: &SplTokenPubkey) -> Pubkey {
|
||||
Pubkey::from_str(&pubkey.to_string()).unwrap()
|
||||
}
|
||||
|
||||
pub fn parse_token(
|
||||
data: &[u8],
|
||||
mint_decimals: Option<u8>,
|
||||
|
@@ -128,7 +128,7 @@ mod test {
|
||||
fn test_parse_vote() {
|
||||
let vote_state = VoteState::default();
|
||||
let mut vote_account_data: Vec<u8> = vec![0; VoteState::size_of()];
|
||||
let versioned = VoteStateVersions::new_current(vote_state);
|
||||
let versioned = VoteStateVersions::Current(Box::new(vote_state));
|
||||
VoteState::serialize(&versioned, &mut vote_account_data).unwrap();
|
||||
let mut expected_vote_state = UiVoteState::default();
|
||||
expected_vote_state.node_pubkey = Pubkey::default().to_string();
|
||||
|
@@ -2,7 +2,7 @@
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-accounts-bench"
|
||||
version = "1.4.26"
|
||||
version = "1.3.24"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -11,11 +11,11 @@ publish = false
|
||||
[dependencies]
|
||||
log = "0.4.6"
|
||||
rayon = "1.4.0"
|
||||
solana-logger = { path = "../logger", version = "1.4.26" }
|
||||
solana-runtime = { path = "../runtime", version = "1.4.26" }
|
||||
solana-measure = { path = "../measure", version = "1.4.26" }
|
||||
solana-sdk = { path = "../sdk", version = "1.4.26" }
|
||||
solana-version = { path = "../version", version = "1.4.26" }
|
||||
solana-logger = { path = "../logger", version = "1.3.24" }
|
||||
solana-runtime = { path = "../runtime", version = "1.3.24" }
|
||||
solana-measure = { path = "../measure", version = "1.3.24" }
|
||||
solana-sdk = { path = "../sdk", version = "1.3.24" }
|
||||
solana-version = { path = "../version", version = "1.3.24" }
|
||||
rand = "0.7.0"
|
||||
clap = "2.33.1"
|
||||
crossbeam-channel = "0.4"
|
||||
|
@@ -88,7 +88,7 @@ fn main() {
|
||||
for x in 0..iterations {
|
||||
if clean {
|
||||
let mut time = Measure::start("clean");
|
||||
accounts.accounts_db.clean_accounts(None);
|
||||
accounts.accounts_db.clean_accounts();
|
||||
time.stop();
|
||||
println!("{}", time);
|
||||
for slot in 0..num_slots {
|
||||
@@ -98,10 +98,7 @@ fn main() {
|
||||
} else {
|
||||
let mut pubkeys: Vec<Pubkey> = vec![];
|
||||
let mut time = Measure::start("hash");
|
||||
let hash = accounts
|
||||
.accounts_db
|
||||
.update_accounts_hash(0, &ancestors, true)
|
||||
.0;
|
||||
let hash = accounts.accounts_db.update_accounts_hash(0, &ancestors).0;
|
||||
time.stop();
|
||||
println!("hash: {} {}", hash, time);
|
||||
create_test_accounts(&accounts, &mut pubkeys, 1, 0);
|
||||
|
@@ -2,7 +2,7 @@
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-banking-bench"
|
||||
version = "1.4.26"
|
||||
version = "1.3.24"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -14,16 +14,16 @@ crossbeam-channel = "0.4"
|
||||
log = "0.4.6"
|
||||
rand = "0.7.0"
|
||||
rayon = "1.4.0"
|
||||
solana-core = { path = "../core", version = "1.4.26" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.4.26" }
|
||||
solana-streamer = { path = "../streamer", version = "1.4.26" }
|
||||
solana-perf = { path = "../perf", version = "1.4.26" }
|
||||
solana-ledger = { path = "../ledger", version = "1.4.26" }
|
||||
solana-logger = { path = "../logger", version = "1.4.26" }
|
||||
solana-runtime = { path = "../runtime", version = "1.4.26" }
|
||||
solana-measure = { path = "../measure", version = "1.4.26" }
|
||||
solana-sdk = { path = "../sdk", version = "1.4.26" }
|
||||
solana-version = { path = "../version", version = "1.4.26" }
|
||||
solana-core = { path = "../core", version = "1.3.24" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.3.24" }
|
||||
solana-streamer = { path = "../streamer", version = "1.3.24" }
|
||||
solana-perf = { path = "../perf", version = "1.3.24" }
|
||||
solana-ledger = { path = "../ledger", version = "1.3.24" }
|
||||
solana-logger = { path = "../logger", version = "1.3.24" }
|
||||
solana-runtime = { path = "../runtime", version = "1.3.24" }
|
||||
solana-measure = { path = "../measure", version = "1.3.24" }
|
||||
solana-sdk = { path = "../sdk", version = "1.3.24" }
|
||||
solana-version = { path = "../version", version = "1.3.24" }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-banks-client"
|
||||
version = "1.4.26"
|
||||
version = "1.3.24"
|
||||
description = "Solana banks client"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -13,15 +13,15 @@ async-trait = "0.1.36"
|
||||
bincode = "1.3.1"
|
||||
futures = "0.3"
|
||||
mio = "0.7.6"
|
||||
solana-banks-interface = { path = "../banks-interface", version = "1.4.26" }
|
||||
solana-sdk = { path = "../sdk", version = "1.4.26" }
|
||||
tarpc = { version = "0.23.0", features = ["full"] }
|
||||
tokio = { version = "0.3", features = ["full"] }
|
||||
solana-banks-interface = { path = "../banks-interface", version = "1.3.24" }
|
||||
solana-sdk = { path = "../sdk", version = "1.3.24" }
|
||||
tarpc = { version = "0.21.0", features = ["full"] }
|
||||
tokio = "0.2"
|
||||
tokio-serde = { version = "0.6", features = ["bincode"] }
|
||||
|
||||
[dev-dependencies]
|
||||
solana-runtime = { path = "../runtime", version = "1.4.26" }
|
||||
solana-banks-server = { path = "../banks-server", version = "1.4.26" }
|
||||
solana-runtime = { path = "../runtime", version = "1.3.24" }
|
||||
solana-banks-server = { path = "../banks-server", version = "1.3.24" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["lib"]
|
||||
|
@@ -10,17 +10,9 @@ use futures::future::join_all;
|
||||
pub use solana_banks_interface::{BanksClient, TransactionStatus};
|
||||
use solana_banks_interface::{BanksRequest, BanksResponse};
|
||||
use solana_sdk::{
|
||||
account::{from_account, Account},
|
||||
clock::Slot,
|
||||
commitment_config::CommitmentLevel,
|
||||
fee_calculator::FeeCalculator,
|
||||
hash::Hash,
|
||||
pubkey::Pubkey,
|
||||
rent::Rent,
|
||||
signature::Signature,
|
||||
sysvar,
|
||||
transaction::Transaction,
|
||||
transport,
|
||||
account::Account, clock::Slot, commitment_config::CommitmentLevel,
|
||||
fee_calculator::FeeCalculator, hash::Hash, pubkey::Pubkey, signature::Signature,
|
||||
transaction::Transaction, transport,
|
||||
};
|
||||
use std::io::{self, Error, ErrorKind};
|
||||
use tarpc::{
|
||||
@@ -48,9 +40,6 @@ pub trait BanksClientExt {
|
||||
/// use them to calculate the transaction fee.
|
||||
async fn get_fees(&mut self) -> io::Result<(FeeCalculator, Hash, Slot)>;
|
||||
|
||||
/// Return the cluster rent
|
||||
async fn get_rent(&mut self) -> io::Result<Rent>;
|
||||
|
||||
/// Send a transaction and return after the transaction has been rejected or
|
||||
/// reached the given level of commitment.
|
||||
async fn process_transaction_with_commitment(
|
||||
@@ -119,17 +108,6 @@ impl BanksClientExt for BanksClient {
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_rent(&mut self) -> io::Result<Rent> {
|
||||
let rent_sysvar = self
|
||||
.get_account(sysvar::rent::id())
|
||||
.await?
|
||||
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Rent sysvar not present"))?;
|
||||
|
||||
from_account::<Rent>(&rent_sysvar).ok_or_else(|| {
|
||||
io::Error::new(io::ErrorKind::Other, "Failed to deserialize Rent sysvar")
|
||||
})
|
||||
}
|
||||
|
||||
async fn get_recent_blockhash(&mut self) -> io::Result<Hash> {
|
||||
Ok(self.get_fees().await?.1)
|
||||
}
|
||||
@@ -226,7 +204,7 @@ pub async fn start_client(
|
||||
}
|
||||
|
||||
pub async fn start_tcp_client<T: ToSocketAddrs>(addr: T) -> io::Result<BanksClient> {
|
||||
let transport = tcp::connect(addr, Bincode::default).await?;
|
||||
let transport = tcp::connect(addr, Bincode::default()).await?;
|
||||
BanksClient::new(client::Config::default(), transport).spawn()
|
||||
}
|
||||
|
||||
@@ -238,7 +216,7 @@ mod tests {
|
||||
use solana_sdk::{message::Message, signature::Signer, system_instruction};
|
||||
use std::sync::{Arc, RwLock};
|
||||
use tarpc::transport;
|
||||
use tokio::{runtime::Runtime, time::sleep};
|
||||
use tokio::{runtime::Runtime, time::delay_for};
|
||||
|
||||
#[test]
|
||||
fn test_banks_client_new() {
|
||||
@@ -307,7 +285,7 @@ mod tests {
|
||||
if root_slot > last_valid_slot {
|
||||
break;
|
||||
}
|
||||
sleep(Duration::from_millis(100)).await;
|
||||
delay_for(Duration::from_millis(100)).await;
|
||||
status = banks_client.get_transaction_status(signature).await?;
|
||||
}
|
||||
assert!(status.unwrap().err.is_none());
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-banks-interface"
|
||||
version = "1.4.26"
|
||||
version = "1.3.24"
|
||||
description = "Solana banks RPC interface"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -11,8 +11,8 @@ edition = "2018"
|
||||
[dependencies]
|
||||
mio = "0.7.6"
|
||||
serde = { version = "1.0.112", features = ["derive"] }
|
||||
solana-sdk = { path = "../sdk", version = "1.4.26" }
|
||||
tarpc = { version = "0.23.0", features = ["full"] }
|
||||
solana-sdk = { path = "../sdk", version = "1.3.24" }
|
||||
tarpc = { version = "0.21.0", features = ["full"] }
|
||||
|
||||
[lib]
|
||||
crate-type = ["lib"]
|
||||
|
@@ -10,19 +10,11 @@ use solana_sdk::{
|
||||
transaction::{self, Transaction, TransactionError},
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum TransactionConfirmationStatus {
|
||||
Processed,
|
||||
Confirmed,
|
||||
Finalized,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct TransactionStatus {
|
||||
pub slot: Slot,
|
||||
pub confirmations: Option<usize>, // None = rooted
|
||||
pub err: Option<TransactionError>,
|
||||
pub confirmation_status: Option<TransactionConfirmationStatus>,
|
||||
}
|
||||
|
||||
#[tarpc::service]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-banks-server"
|
||||
version = "1.4.26"
|
||||
version = "1.3.24"
|
||||
description = "Solana banks server"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -13,12 +13,12 @@ bincode = "1.3.1"
|
||||
futures = "0.3"
|
||||
log = "0.4.8"
|
||||
mio = "0.7.6"
|
||||
solana-banks-interface = { path = "../banks-interface", version = "1.4.26" }
|
||||
solana-runtime = { path = "../runtime", version = "1.4.26" }
|
||||
solana-sdk = { path = "../sdk", version = "1.4.26" }
|
||||
solana-metrics = { path = "../metrics", version = "1.4.26" }
|
||||
tarpc = { version = "0.23.0", features = ["full"] }
|
||||
tokio = { version = "0.3", features = ["full"] }
|
||||
solana-banks-interface = { path = "../banks-interface", version = "1.3.24" }
|
||||
solana-runtime = { path = "../runtime", version = "1.3.24" }
|
||||
solana-sdk = { path = "../sdk", version = "1.3.24" }
|
||||
solana-metrics = { path = "../metrics", version = "1.3.24" }
|
||||
tarpc = { version = "0.21.0", features = ["full"] }
|
||||
tokio = "0.2"
|
||||
tokio-serde = { version = "0.6", features = ["bincode"] }
|
||||
|
||||
[lib]
|
||||
|
@@ -4,10 +4,12 @@ use futures::{
|
||||
future,
|
||||
prelude::stream::{self, StreamExt},
|
||||
};
|
||||
use solana_banks_interface::{
|
||||
Banks, BanksRequest, BanksResponse, TransactionConfirmationStatus, TransactionStatus,
|
||||
use solana_banks_interface::{Banks, BanksRequest, BanksResponse, TransactionStatus};
|
||||
use solana_runtime::{
|
||||
bank::Bank,
|
||||
bank_forks::BankForks,
|
||||
commitment::{BlockCommitmentCache, CommitmentSlots},
|
||||
};
|
||||
use solana_runtime::{bank::Bank, bank_forks::BankForks, commitment::BlockCommitmentCache};
|
||||
use solana_sdk::{
|
||||
account::Account,
|
||||
clock::Slot,
|
||||
@@ -19,6 +21,7 @@ use solana_sdk::{
|
||||
transaction::{self, Transaction},
|
||||
};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
io,
|
||||
net::{Ipv4Addr, SocketAddr},
|
||||
sync::{
|
||||
@@ -35,7 +38,7 @@ use tarpc::{
|
||||
server::{self, Channel, Handler},
|
||||
transport,
|
||||
};
|
||||
use tokio::time::sleep;
|
||||
use tokio::time::delay_for;
|
||||
use tokio_serde::formats::Bincode;
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -81,9 +84,16 @@ impl BanksServer {
|
||||
let (transaction_sender, transaction_receiver) = channel();
|
||||
let bank = bank_forks.read().unwrap().working_bank();
|
||||
let slot = bank.slot();
|
||||
let block_commitment_cache = Arc::new(RwLock::new(
|
||||
BlockCommitmentCache::new_for_tests_with_slots(slot, slot),
|
||||
));
|
||||
let block_commitment_cache = Arc::new(RwLock::new(BlockCommitmentCache::new(
|
||||
HashMap::default(),
|
||||
0,
|
||||
CommitmentSlots {
|
||||
slot,
|
||||
root: 0,
|
||||
highest_confirmed_slot: 0,
|
||||
highest_confirmed_root: 0,
|
||||
},
|
||||
)));
|
||||
Builder::new()
|
||||
.name("solana-bank-forks-client".to_string())
|
||||
.spawn(move || Self::run(&bank, transaction_receiver))
|
||||
@@ -104,36 +114,23 @@ impl BanksServer {
|
||||
|
||||
async fn poll_signature_status(
|
||||
self,
|
||||
signature: &Signature,
|
||||
blockhash: &Hash,
|
||||
signature: Signature,
|
||||
last_valid_slot: Slot,
|
||||
commitment: CommitmentLevel,
|
||||
) -> Option<transaction::Result<()>> {
|
||||
let mut status = self
|
||||
.bank(commitment)
|
||||
.get_signature_status_with_blockhash(signature, blockhash);
|
||||
let mut status = self.bank(commitment).get_signature_status(&signature);
|
||||
while status.is_none() {
|
||||
sleep(Duration::from_millis(200)).await;
|
||||
delay_for(Duration::from_millis(200)).await;
|
||||
let bank = self.bank(commitment);
|
||||
if bank.slot() > last_valid_slot {
|
||||
break;
|
||||
}
|
||||
status = bank.get_signature_status_with_blockhash(signature, blockhash);
|
||||
status = bank.get_signature_status(&signature);
|
||||
}
|
||||
status
|
||||
}
|
||||
}
|
||||
|
||||
fn verify_transaction(transaction: &Transaction) -> transaction::Result<()> {
|
||||
if let Err(err) = transaction.verify() {
|
||||
Err(err)
|
||||
} else if let Err(err) = transaction.verify_precompiles() {
|
||||
Err(err)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[tarpc::server]
|
||||
impl Banks for BanksServer {
|
||||
async fn send_transaction_with_context(self, _: Context, transaction: Transaction) {
|
||||
@@ -171,13 +168,7 @@ impl Banks for BanksServer {
|
||||
let (slot, status) = bank.get_signature_status_slot(&signature)?;
|
||||
let r_block_commitment_cache = self.block_commitment_cache.read().unwrap();
|
||||
|
||||
let optimistically_confirmed_bank = self.bank(CommitmentLevel::SingleGossip);
|
||||
let optimistically_confirmed =
|
||||
optimistically_confirmed_bank.get_signature_status_slot(&signature);
|
||||
|
||||
let confirmations = if r_block_commitment_cache.root() >= slot
|
||||
&& r_block_commitment_cache.highest_confirmed_root() >= slot
|
||||
{
|
||||
let confirmations = if r_block_commitment_cache.root() >= slot {
|
||||
None
|
||||
} else {
|
||||
r_block_commitment_cache
|
||||
@@ -188,13 +179,6 @@ impl Banks for BanksServer {
|
||||
slot,
|
||||
confirmations,
|
||||
err: status.err(),
|
||||
confirmation_status: if confirmations.is_none() {
|
||||
Some(TransactionConfirmationStatus::Finalized)
|
||||
} else if optimistically_confirmed.is_some() {
|
||||
Some(TransactionConfirmationStatus::Confirmed)
|
||||
} else {
|
||||
Some(TransactionConfirmationStatus::Processed)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -208,23 +192,19 @@ impl Banks for BanksServer {
|
||||
transaction: Transaction,
|
||||
commitment: CommitmentLevel,
|
||||
) -> Option<transaction::Result<()>> {
|
||||
if let Err(err) = verify_transaction(&transaction) {
|
||||
return Some(Err(err));
|
||||
}
|
||||
|
||||
let blockhash = &transaction.message.recent_blockhash;
|
||||
let last_valid_slot = self
|
||||
.bank_forks
|
||||
.read()
|
||||
.unwrap()
|
||||
.root_bank()
|
||||
.get_blockhash_last_valid_slot(blockhash)
|
||||
.get_blockhash_last_valid_slot(&blockhash)
|
||||
.unwrap();
|
||||
let signature = transaction.signatures.get(0).cloned().unwrap_or_default();
|
||||
let info =
|
||||
TransactionInfo::new(signature, serialize(&transaction).unwrap(), last_valid_slot);
|
||||
self.transaction_sender.send(info).unwrap();
|
||||
self.poll_signature_status(&signature, blockhash, last_valid_slot, commitment)
|
||||
self.poll_signature_status(signature, last_valid_slot, commitment)
|
||||
.await
|
||||
}
|
||||
|
||||
|
@@ -2,7 +2,7 @@
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-bench-exchange"
|
||||
version = "1.4.26"
|
||||
version = "1.3.24"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -18,21 +18,21 @@ rand = "0.7.0"
|
||||
rayon = "1.4.0"
|
||||
serde_json = "1.0.56"
|
||||
serde_yaml = "0.8.13"
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.4.26" }
|
||||
solana-core = { path = "../core", version = "1.4.26" }
|
||||
solana-genesis = { path = "../genesis", version = "1.4.26" }
|
||||
solana-client = { path = "../client", version = "1.4.26" }
|
||||
solana-faucet = { path = "../faucet", version = "1.4.26" }
|
||||
solana-exchange-program = { path = "../programs/exchange", version = "1.4.26" }
|
||||
solana-logger = { path = "../logger", version = "1.4.26" }
|
||||
solana-metrics = { path = "../metrics", version = "1.4.26" }
|
||||
solana-net-utils = { path = "../net-utils", version = "1.4.26" }
|
||||
solana-runtime = { path = "../runtime", version = "1.4.26" }
|
||||
solana-sdk = { path = "../sdk", version = "1.4.26" }
|
||||
solana-version = { path = "../version", version = "1.4.26" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.3.24" }
|
||||
solana-core = { path = "../core", version = "1.3.24" }
|
||||
solana-genesis = { path = "../genesis", version = "1.3.24" }
|
||||
solana-client = { path = "../client", version = "1.3.24" }
|
||||
solana-faucet = { path = "../faucet", version = "1.3.24" }
|
||||
solana-exchange-program = { path = "../programs/exchange", version = "1.3.24" }
|
||||
solana-logger = { path = "../logger", version = "1.3.24" }
|
||||
solana-metrics = { path = "../metrics", version = "1.3.24" }
|
||||
solana-net-utils = { path = "../net-utils", version = "1.3.24" }
|
||||
solana-runtime = { path = "../runtime", version = "1.3.24" }
|
||||
solana-sdk = { path = "../sdk", version = "1.3.24" }
|
||||
solana-version = { path = "../version", version = "1.3.24" }
|
||||
|
||||
[dev-dependencies]
|
||||
solana-local-cluster = { path = "../local-cluster", version = "1.4.26" }
|
||||
solana-local-cluster = { path = "../local-cluster", version = "1.3.24" }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
@@ -39,7 +39,7 @@ fn test_exchange_local_cluster() {
|
||||
} = config;
|
||||
let accounts_in_groups = batch_size * account_groups;
|
||||
|
||||
let cluster = LocalCluster::new(&mut ClusterConfig {
|
||||
let cluster = LocalCluster::new(&ClusterConfig {
|
||||
node_stakes: vec![100_000; NUM_NODES],
|
||||
cluster_lamports: 100_000_000_000_000,
|
||||
validator_configs: vec![ValidatorConfig::default(); NUM_NODES],
|
||||
@@ -86,7 +86,7 @@ fn test_exchange_bank_client() {
|
||||
solana_logger::setup();
|
||||
let (genesis_config, identity) = create_genesis_config(100_000_000_000_000);
|
||||
let mut bank = Bank::new(&genesis_config);
|
||||
bank.add_builtin("exchange_program", id(), process_instruction);
|
||||
bank.add_builtin_program("exchange_program", id(), process_instruction);
|
||||
let clients = vec![BankClient::new(bank)];
|
||||
|
||||
let mut config = Config::default();
|
||||
|
@@ -2,7 +2,7 @@
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-bench-streamer"
|
||||
version = "1.4.26"
|
||||
version = "1.3.24"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -10,11 +10,11 @@ publish = false
|
||||
|
||||
[dependencies]
|
||||
clap = "2.33.1"
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.4.26" }
|
||||
solana-streamer = { path = "../streamer", version = "1.4.26" }
|
||||
solana-logger = { path = "../logger", version = "1.4.26" }
|
||||
solana-net-utils = { path = "../net-utils", version = "1.4.26" }
|
||||
solana-version = { path = "../version", version = "1.4.26" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.3.24" }
|
||||
solana-streamer = { path = "../streamer", version = "1.3.24" }
|
||||
solana-logger = { path = "../logger", version = "1.3.24" }
|
||||
solana-net-utils = { path = "../net-utils", version = "1.3.24" }
|
||||
solana-version = { path = "../version", version = "1.3.24" }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
@@ -2,7 +2,7 @@
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-bench-tps"
|
||||
version = "1.4.26"
|
||||
version = "1.3.24"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -15,23 +15,23 @@ log = "0.4.8"
|
||||
rayon = "1.4.0"
|
||||
serde_json = "1.0.56"
|
||||
serde_yaml = "0.8.13"
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.4.26" }
|
||||
solana-core = { path = "../core", version = "1.4.26" }
|
||||
solana-genesis = { path = "../genesis", version = "1.4.26" }
|
||||
solana-client = { path = "../client", version = "1.4.26" }
|
||||
solana-faucet = { path = "../faucet", version = "1.4.26" }
|
||||
solana-logger = { path = "../logger", version = "1.4.26" }
|
||||
solana-metrics = { path = "../metrics", version = "1.4.26" }
|
||||
solana-measure = { path = "../measure", version = "1.4.26" }
|
||||
solana-net-utils = { path = "../net-utils", version = "1.4.26" }
|
||||
solana-runtime = { path = "../runtime", version = "1.4.26" }
|
||||
solana-sdk = { path = "../sdk", version = "1.4.26" }
|
||||
solana-version = { path = "../version", version = "1.4.26" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.3.24" }
|
||||
solana-core = { path = "../core", version = "1.3.24" }
|
||||
solana-genesis = { path = "../genesis", version = "1.3.24" }
|
||||
solana-client = { path = "../client", version = "1.3.24" }
|
||||
solana-faucet = { path = "../faucet", version = "1.3.24" }
|
||||
solana-logger = { path = "../logger", version = "1.3.24" }
|
||||
solana-metrics = { path = "../metrics", version = "1.3.24" }
|
||||
solana-measure = { path = "../measure", version = "1.3.24" }
|
||||
solana-net-utils = { path = "../net-utils", version = "1.3.24" }
|
||||
solana-runtime = { path = "../runtime", version = "1.3.24" }
|
||||
solana-sdk = { path = "../sdk", version = "1.3.24" }
|
||||
solana-version = { path = "../version", version = "1.3.24" }
|
||||
|
||||
[dev-dependencies]
|
||||
serial_test = "0.4.0"
|
||||
serial_test_derive = "0.4.0"
|
||||
solana-local-cluster = { path = "../local-cluster", version = "1.4.26" }
|
||||
solana-local-cluster = { path = "../local-cluster", version = "1.3.24" }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
@@ -15,7 +15,7 @@ fn test_bench_tps_local_cluster(config: Config) {
|
||||
|
||||
solana_logger::setup();
|
||||
const NUM_NODES: usize = 1;
|
||||
let cluster = LocalCluster::new(&mut ClusterConfig {
|
||||
let cluster = LocalCluster::new(&ClusterConfig {
|
||||
node_stakes: vec![999_990; NUM_NODES],
|
||||
cluster_lamports: 200_000_000,
|
||||
validator_configs: vec![ValidatorConfig::default(); NUM_NODES],
|
||||
|
@@ -1,13 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
here=$(dirname "$0")
|
||||
|
||||
maybe_bpf_sdk="--bpf-sdk $here/sdk/bpf"
|
||||
for a in "$@"; do
|
||||
if [[ $a = --bpf-sdk ]]; then
|
||||
maybe_bpf_sdk=
|
||||
fi
|
||||
done
|
||||
|
||||
set -x
|
||||
exec "$here"/cargo run --manifest-path "$here"/sdk/cargo-build-bpf/Cargo.toml -- $maybe_bpf_sdk "$@"
|
@@ -1,14 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
here=$(dirname "$0")
|
||||
|
||||
maybe_bpf_sdk="--bpf-sdk $here/sdk/bpf"
|
||||
for a in "$@"; do
|
||||
if [[ $a = --bpf-sdk ]]; then
|
||||
maybe_bpf_sdk=
|
||||
fi
|
||||
done
|
||||
|
||||
export CARGO_BUILD_BPF="$here"/cargo-build-bpf
|
||||
set -x
|
||||
exec "$here"/cargo run --manifest-path "$here"/sdk/cargo-test-bpf/Cargo.toml -- $maybe_bpf_sdk "$@"
|
@@ -175,30 +175,6 @@ EOF
|
||||
"Stable-perf skipped as no relevant files were modified"
|
||||
fi
|
||||
|
||||
# Downstream backwards compatibility
|
||||
if affects \
|
||||
.rs$ \
|
||||
Cargo.lock$ \
|
||||
Cargo.toml$ \
|
||||
^ci/rust-version.sh \
|
||||
^ci/test-stable-perf.sh \
|
||||
^ci/test-stable.sh \
|
||||
^ci/test-local-cluster.sh \
|
||||
^core/build.rs \
|
||||
^fetch-perf-libs.sh \
|
||||
^programs/ \
|
||||
^sdk/ \
|
||||
^scripts/build-downstream-projects.sh \
|
||||
; then
|
||||
cat >> "$output_file" <<"EOF"
|
||||
- command: "scripts/build-downstream-projects.sh"
|
||||
name: "downstream-projects"
|
||||
timeout_in_minutes: 30
|
||||
EOF
|
||||
else
|
||||
annotate --style info \
|
||||
"downstream-projects skipped as no relevant files were modified"
|
||||
fi
|
||||
# Benches...
|
||||
if affects \
|
||||
.rs$ \
|
||||
|
@@ -95,14 +95,12 @@ elif [[ -n $CI_BRANCH ]]; then
|
||||
BRANCH="$CI_BRANCH"
|
||||
fi
|
||||
|
||||
if [[ -z "$CHANNEL" ]]; then
|
||||
if [[ $BRANCH = "$STABLE_CHANNEL" ]]; then
|
||||
CHANNEL=stable
|
||||
elif [[ $BRANCH = "$EDGE_CHANNEL" ]]; then
|
||||
CHANNEL=edge
|
||||
elif [[ $BRANCH = "$BETA_CHANNEL" ]]; then
|
||||
CHANNEL=beta
|
||||
fi
|
||||
if [[ $BRANCH = "$STABLE_CHANNEL" ]]; then
|
||||
CHANNEL=stable
|
||||
elif [[ $BRANCH = "$EDGE_CHANNEL" ]]; then
|
||||
CHANNEL=edge
|
||||
elif [[ $BRANCH = "$BETA_CHANNEL" ]]; then
|
||||
CHANNEL=beta
|
||||
fi
|
||||
|
||||
echo EDGE_CHANNEL="$EDGE_CHANNEL"
|
||||
|
@@ -1,4 +1,4 @@
|
||||
FROM solanalabs/rust:1.46.0
|
||||
FROM solanalabs/rust:1.45.1
|
||||
ARG date
|
||||
|
||||
RUN set -x \
|
||||
|
@@ -20,7 +20,7 @@ To update the pinned version:
|
||||
specific YYYY-MM-DD that is desired (default is today's build).
|
||||
Check https://rust-lang.github.io/rustup-components-history/ for build
|
||||
status
|
||||
1. Update `ci/rust-version.sh` to reflect the new nightly `YYYY-MM-DD`
|
||||
1. Update `ci/rust-version.sh` to reflect the new nightly `YYY-MM-DD`
|
||||
1. Run `SOLANA_ALLOCATE_TTY=1 SOLANA_DOCKER_RUN_NOSETUID=1 ci/docker-run.sh --nopull solanalabs/rust-nightly:YYYY-MM-DD ci/test-checks.sh`
|
||||
and `SOLANA_ALLOCATE_TTY=1 SOLANA_DOCKER_RUN_NOSETUID=1 ci/docker-run.sh --nopull solanalabs/rust-nightly:YYYY-MM-DD ci/test-coverage.sh [args]...`
|
||||
to confirm the new nightly image builds. Fix any issues as needed
|
||||
|
@@ -1,6 +1,6 @@
|
||||
# Note: when the rust version is changed also modify
|
||||
# ci/rust-version.sh to pick up the new image tag
|
||||
FROM rust:1.46.0
|
||||
FROM rust:1.45.1
|
||||
|
||||
# Add Google Protocol Buffers for Libra's metrics library.
|
||||
ENV PROTOC_VERSION 3.8.0
|
||||
|
@@ -26,9 +26,7 @@ declare print_free_tree=(
|
||||
':runtime/src/**.rs'
|
||||
':sdk/bpf/rust/rust-utils/**.rs'
|
||||
':sdk/**.rs'
|
||||
':^sdk/cargo-build-bpf/**.rs'
|
||||
':^sdk/program/src/program_option.rs'
|
||||
':^sdk/program/src/program_stubs.rs'
|
||||
':^sdk/src/program_option.rs'
|
||||
':programs/**.rs'
|
||||
':^**bin**.rs'
|
||||
':^**bench**.rs'
|
||||
|
@@ -4,8 +4,6 @@ cd "$(dirname "$0")/.."
|
||||
source ci/semver_bash/semver.sh
|
||||
source ci/rust-version.sh stable
|
||||
|
||||
cargo="$(readlink -f ./cargo)"
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
is_crate_version_uploaded() {
|
||||
name=$1
|
||||
@@ -40,7 +38,7 @@ for Cargo_toml in $Cargo_tomls; do
|
||||
crate_name=$(grep -m 1 '^name = ' "$Cargo_toml" | cut -f 3 -d ' ' | tr -d \")
|
||||
|
||||
if grep -q "^publish = false" "$Cargo_toml"; then
|
||||
echo "$crate_name is marked as unpublishable"
|
||||
echo "$crate_name is is marked as unpublishable"
|
||||
continue
|
||||
fi
|
||||
|
||||
@@ -68,11 +66,11 @@ for Cargo_toml in $Cargo_tomls; do
|
||||
(
|
||||
set -x
|
||||
rm -rf crate-test
|
||||
"$cargo" stable init crate-test
|
||||
cargo +"$rust_stable" init crate-test
|
||||
cd crate-test/
|
||||
echo "${crate_name} = \"${expectedCrateVersion}\"" >> Cargo.toml
|
||||
echo "[workspace]" >> Cargo.toml
|
||||
"$cargo" stable check
|
||||
cargo +"$rust_stable" check
|
||||
) && really_uploaded=1
|
||||
if ((really_uploaded)); then
|
||||
break;
|
||||
|
@@ -18,13 +18,13 @@
|
||||
if [[ -n $RUST_STABLE_VERSION ]]; then
|
||||
stable_version="$RUST_STABLE_VERSION"
|
||||
else
|
||||
stable_version=1.46.0
|
||||
stable_version=1.45.1
|
||||
fi
|
||||
|
||||
if [[ -n $RUST_NIGHTLY_VERSION ]]; then
|
||||
nightly_version="$RUST_NIGHTLY_VERSION"
|
||||
else
|
||||
nightly_version=2020-08-17
|
||||
nightly_version=2020-07-27
|
||||
fi
|
||||
|
||||
|
||||
|
@@ -6,8 +6,7 @@ source ci/_
|
||||
source ci/upload-ci-artifact.sh
|
||||
|
||||
eval "$(ci/channel-info.sh)"
|
||||
|
||||
cargo="$(readlink -f "./cargo")"
|
||||
source ci/rust-version.sh all
|
||||
|
||||
set -o pipefail
|
||||
export RUST_BACKTRACE=1
|
||||
@@ -28,35 +27,35 @@ test -d target/debug/bpf && find target/debug/bpf -name '*.d' -delete
|
||||
test -d target/release/bpf && find target/release/bpf -name '*.d' -delete
|
||||
|
||||
# Ensure all dependencies are built
|
||||
_ "$cargo" nightly build --release
|
||||
_ cargo +$rust_nightly build --release
|
||||
|
||||
# Remove "BENCH_FILE", if it exists so that the following commands can append
|
||||
rm -f "$BENCH_FILE"
|
||||
|
||||
# Run sdk benches
|
||||
_ "$cargo" nightly bench --manifest-path sdk/Cargo.toml ${V:+--verbose} \
|
||||
_ cargo +$rust_nightly bench --manifest-path sdk/Cargo.toml ${V:+--verbose} \
|
||||
-- -Z unstable-options --format=json | tee -a "$BENCH_FILE"
|
||||
|
||||
# Run runtime benches
|
||||
_ "$cargo" nightly bench --manifest-path runtime/Cargo.toml ${V:+--verbose} \
|
||||
_ cargo +$rust_nightly bench --manifest-path runtime/Cargo.toml ${V:+--verbose} \
|
||||
-- -Z unstable-options --format=json | tee -a "$BENCH_FILE"
|
||||
|
||||
# Run core benches
|
||||
_ "$cargo" nightly bench --manifest-path core/Cargo.toml ${V:+--verbose} \
|
||||
_ cargo +$rust_nightly bench --manifest-path core/Cargo.toml ${V:+--verbose} \
|
||||
-- -Z unstable-options --format=json | tee -a "$BENCH_FILE"
|
||||
|
||||
# Run bpf benches
|
||||
_ "$cargo" nightly bench --manifest-path programs/bpf/Cargo.toml ${V:+--verbose} --features=bpf_c \
|
||||
_ cargo +$rust_nightly bench --manifest-path programs/bpf/Cargo.toml ${V:+--verbose} --features=bpf_c \
|
||||
-- -Z unstable-options --format=json --nocapture | tee -a "$BENCH_FILE"
|
||||
|
||||
# Run banking/accounts bench. Doesn't require nightly, but use since it is already built.
|
||||
_ "$cargo" nightly run --release --manifest-path banking-bench/Cargo.toml ${V:+--verbose} | tee -a "$BENCH_FILE"
|
||||
_ "$cargo" nightly run --release --manifest-path accounts-bench/Cargo.toml ${V:+--verbose} -- --num_accounts 10000 --num_slots 4 | tee -a "$BENCH_FILE"
|
||||
_ cargo +$rust_nightly run --release --manifest-path banking-bench/Cargo.toml ${V:+--verbose} | tee -a "$BENCH_FILE"
|
||||
_ cargo +$rust_nightly run --release --manifest-path accounts-bench/Cargo.toml ${V:+--verbose} -- --num_accounts 10000 --num_slots 4 | tee -a "$BENCH_FILE"
|
||||
|
||||
# `solana-upload-perf` disabled as it can take over 30 minutes to complete for some
|
||||
# reason
|
||||
exit 0
|
||||
_ "$cargo" nightly run --release --package solana-upload-perf \
|
||||
_ cargo +$rust_nightly run --release --package solana-upload-perf \
|
||||
-- "$BENCH_FILE" "$TARGET_BRANCH" "$UPLOAD_METRICS" | tee "$BENCH_ARTIFACT"
|
||||
|
||||
upload-ci-artifact "$BENCH_FILE"
|
||||
|
@@ -8,7 +8,6 @@ source ci/_
|
||||
source ci/rust-version.sh stable
|
||||
source ci/rust-version.sh nightly
|
||||
eval "$(ci/channel-info.sh)"
|
||||
cargo="$(readlink -f "./cargo")"
|
||||
|
||||
scripts/increment-cargo-version.sh check
|
||||
|
||||
@@ -19,14 +18,14 @@ echo --- build environment
|
||||
rustup run "$rust_stable" rustc --version --verbose
|
||||
rustup run "$rust_nightly" rustc --version --verbose
|
||||
|
||||
"$cargo" stable --version --verbose
|
||||
"$cargo" nightly --version --verbose
|
||||
cargo +"$rust_stable" --version --verbose
|
||||
cargo +"$rust_nightly" --version --verbose
|
||||
|
||||
"$cargo" stable clippy --version --verbose
|
||||
"$cargo" nightly clippy --version --verbose
|
||||
cargo +"$rust_stable" clippy --version --verbose
|
||||
cargo +"$rust_nightly" clippy --version --verbose
|
||||
|
||||
# audit is done only with stable
|
||||
"$cargo" stable audit --version
|
||||
cargo +"$rust_stable" audit --version
|
||||
)
|
||||
|
||||
export RUST_BACKTRACE=1
|
||||
@@ -47,18 +46,18 @@ if [[ $CI_BASE_BRANCH = "$EDGE_CHANNEL" ]]; then
|
||||
|
||||
# Ensure nightly and --benches
|
||||
_ scripts/cargo-for-all-lock-files.sh +"$rust_nightly" check --locked --all-targets
|
||||
|
||||
else
|
||||
echo "Note: cargo-for-all-lock-files.sh skipped because $CI_BASE_BRANCH != $EDGE_CHANNEL"
|
||||
fi
|
||||
|
||||
_ ci/order-crates-for-publishing.py
|
||||
_ "$cargo" stable fmt --all -- --check
|
||||
_ cargo +"$rust_stable" fmt --all -- --check
|
||||
|
||||
# -Z... is needed because of clippy bug: https://github.com/rust-lang/rust-clippy/issues/4612
|
||||
# run nightly clippy for `sdk/` as there's a moderate amount of nightly-only code there
|
||||
_ "$cargo" nightly clippy \
|
||||
-Zunstable-options --workspace --all-targets \
|
||||
-- --deny=warnings --allow=clippy::stable_sort_primitive
|
||||
_ cargo +"$rust_nightly" clippy -Zunstable-options --workspace --all-targets -- --deny=warnings
|
||||
|
||||
|
||||
cargo_audit_ignores=(
|
||||
# failure is officially deprecated/unmaintained
|
||||
@@ -81,26 +80,23 @@ cargo_audit_ignores=(
|
||||
# Blocked on multiple crates updating `time` to >= 0.2.23
|
||||
--ignore RUSTSEC-2020-0071
|
||||
|
||||
# difference is unmaintained
|
||||
# memmap crate is unmaintained
|
||||
#
|
||||
# Blocked on predicates v1.0.6 removing its dependency on `difference`
|
||||
--ignore RUSTSEC-2020-0095
|
||||
|
||||
# Blocked on us releasing new solana crates
|
||||
--ignore RUSTSEC-2020-0077
|
||||
)
|
||||
_ scripts/cargo-for-all-lock-files.sh +"$rust_stable" audit "${cargo_audit_ignores[@]}"
|
||||
|
||||
{
|
||||
cd programs/bpf
|
||||
_ "$cargo" stable audit
|
||||
_ cargo +"$rust_stable" audit
|
||||
for project in rust/*/ ; do
|
||||
echo "+++ do_bpf_checks $project"
|
||||
(
|
||||
cd "$project"
|
||||
_ "$cargo" stable fmt -- --check
|
||||
_ "$cargo" nightly test
|
||||
_ "$cargo" nightly clippy -- --deny=warnings \
|
||||
--allow=clippy::missing_safety_doc \
|
||||
--allow=clippy::stable_sort_primitive
|
||||
_ cargo +"$rust_stable" fmt -- --check
|
||||
_ cargo +"$rust_nightly" test
|
||||
_ cargo +"$rust_nightly" clippy -- --deny=warnings --allow=clippy::missing_safety_doc
|
||||
)
|
||||
done
|
||||
}
|
||||
|
@@ -2,8 +2,6 @@
|
||||
set -e
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
cargo="$(readlink -f "./cargo")"
|
||||
|
||||
source ci/_
|
||||
|
||||
annotate() {
|
||||
@@ -39,15 +37,12 @@ NPROC=$((NPROC>14 ? 14 : NPROC))
|
||||
echo "Executing $testName"
|
||||
case $testName in
|
||||
test-stable)
|
||||
_ "$cargo" stable test --jobs "$NPROC" --all --exclude solana-local-cluster ${V:+--verbose} -- --nocapture
|
||||
_ cargo +"$rust_stable" test --jobs "$NPROC" --all --exclude solana-local-cluster ${V:+--verbose} -- --nocapture
|
||||
;;
|
||||
test-stable-perf)
|
||||
# BPF solana-sdk legacy compile test
|
||||
./cargo-build-bpf --manifest-path sdk/Cargo.toml
|
||||
|
||||
# BPF program tests
|
||||
_ make -C programs/bpf/c tests
|
||||
_ "$cargo" stable test \
|
||||
_ cargo +"$rust_stable" test \
|
||||
--manifest-path programs/bpf/Cargo.toml \
|
||||
--no-default-features --features=bpf_c,bpf_rust -- --nocapture
|
||||
|
||||
@@ -67,13 +62,13 @@ test-stable-perf)
|
||||
export SOLANA_CUDA=1
|
||||
fi
|
||||
|
||||
_ "$cargo" stable build --bins ${V:+--verbose}
|
||||
_ "$cargo" stable test --package solana-perf --package solana-ledger --package solana-core --lib ${V:+--verbose} -- --nocapture
|
||||
_ "$cargo" stable run --manifest-path poh-bench/Cargo.toml ${V:+--verbose} -- --hashes-per-tick 10
|
||||
_ cargo +"$rust_stable" build --bins ${V:+--verbose}
|
||||
_ cargo +"$rust_stable" test --package solana-perf --package solana-ledger --package solana-core --lib ${V:+--verbose} -- --nocapture
|
||||
_ cargo +"$rust_stable" run --manifest-path poh-bench/Cargo.toml ${V:+--verbose} -- --hashes-per-tick 10
|
||||
;;
|
||||
test-local-cluster)
|
||||
_ "$cargo" stable build --release --bins ${V:+--verbose}
|
||||
_ "$cargo" stable test --release --package solana-local-cluster ${V:+--verbose} -- --nocapture --test-threads=1
|
||||
_ cargo +"$rust_stable" build --release --bins ${V:+--verbose}
|
||||
_ cargo +"$rust_stable" test --release --package solana-local-cluster ${V:+--verbose} -- --nocapture --test-threads=1
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-clap-utils"
|
||||
version = "1.4.26"
|
||||
version = "1.3.24"
|
||||
description = "Solana utilities for the clap"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -11,8 +11,8 @@ edition = "2018"
|
||||
[dependencies]
|
||||
clap = "2.33.0"
|
||||
rpassword = "4.0"
|
||||
solana-remote-wallet = { path = "../remote-wallet", version = "1.4.26" }
|
||||
solana-sdk = { path = "../sdk", version = "1.4.26" }
|
||||
solana-remote-wallet = { path = "../remote-wallet", version = "1.3.24" }
|
||||
solana-sdk = { path = "../sdk", version = "1.3.24" }
|
||||
thiserror = "1.0.20"
|
||||
tiny-bip39 = "0.7.0"
|
||||
url = "2.1.0"
|
||||
|
22
clap-utils/src/commitment.rs
Normal file
22
clap-utils/src/commitment.rs
Normal file
@@ -0,0 +1,22 @@
|
||||
use crate::ArgConstant;
|
||||
use clap::Arg;
|
||||
|
||||
pub const COMMITMENT_ARG: ArgConstant<'static> = ArgConstant {
|
||||
name: "commitment",
|
||||
long: "commitment",
|
||||
help: "Return information at the selected commitment level",
|
||||
};
|
||||
|
||||
pub fn commitment_arg<'a, 'b>() -> Arg<'a, 'b> {
|
||||
commitment_arg_with_default("recent")
|
||||
}
|
||||
|
||||
pub fn commitment_arg_with_default<'a, 'b>(default_value: &'static str) -> Arg<'a, 'b> {
|
||||
Arg::with_name(COMMITMENT_ARG.name)
|
||||
.long(COMMITMENT_ARG.long)
|
||||
.takes_value(true)
|
||||
.possible_values(&["recent", "single", "singleGossip", "root", "max"])
|
||||
.default_value(default_value)
|
||||
.value_name("COMMITMENT_LEVEL")
|
||||
.help(COMMITMENT_ARG.help)
|
||||
}
|
@@ -184,9 +184,13 @@ pub fn cluster_type_of(matches: &ArgMatches<'_>, name: &str) -> Option<ClusterTy
|
||||
}
|
||||
|
||||
pub fn commitment_of(matches: &ArgMatches<'_>, name: &str) -> Option<CommitmentConfig> {
|
||||
matches
|
||||
.value_of(name)
|
||||
.map(|value| CommitmentConfig::from_str(value).unwrap_or_default())
|
||||
matches.value_of(name).map(|value| match value {
|
||||
"max" => CommitmentConfig::max(),
|
||||
"recent" => CommitmentConfig::recent(),
|
||||
"root" => CommitmentConfig::root(),
|
||||
"single" => CommitmentConfig::single(),
|
||||
_ => CommitmentConfig::default(),
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@@ -1,7 +1,7 @@
|
||||
use crate::keypair::{parse_keypair_path, KeypairUrl, ASK_KEYWORD};
|
||||
use chrono::DateTime;
|
||||
use solana_sdk::{
|
||||
clock::{Epoch, Slot},
|
||||
clock::Slot,
|
||||
hash::Hash,
|
||||
pubkey::Pubkey,
|
||||
signature::{read_keypair_file, Signature},
|
||||
@@ -148,40 +148,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_url_or_moniker<T>(string: T) -> Result<(), String>
|
||||
where
|
||||
T: AsRef<str> + Display,
|
||||
{
|
||||
match url::Url::parse(&normalize_to_url_if_moniker(string.as_ref())) {
|
||||
Ok(url) => {
|
||||
if url.has_host() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err("no host provided".to_string())
|
||||
}
|
||||
}
|
||||
Err(err) => Err(format!("{}", err)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn normalize_to_url_if_moniker(url_or_moniker: &str) -> String {
|
||||
match url_or_moniker {
|
||||
"m" | "mainnet-beta" => "https://api.mainnet-beta.solana.com",
|
||||
"t" | "testnet" => "https://testnet.solana.com",
|
||||
"d" | "devnet" => "https://devnet.solana.com",
|
||||
"l" | "localhost" => "http://localhost:8899",
|
||||
url => url,
|
||||
}
|
||||
.to_string()
|
||||
}
|
||||
|
||||
pub fn is_epoch<T>(epoch: T) -> Result<(), String>
|
||||
where
|
||||
T: AsRef<str> + Display,
|
||||
{
|
||||
is_parsable_generic::<Epoch, _>(epoch)
|
||||
}
|
||||
|
||||
pub fn is_slot<T>(slot: T) -> Result<(), String>
|
||||
where
|
||||
T: AsRef<str> + Display,
|
||||
|
@@ -58,15 +58,6 @@ impl CliSignerInfo {
|
||||
Some(0)
|
||||
}
|
||||
}
|
||||
pub fn index_of_or_none(&self, pubkey: Option<Pubkey>) -> Option<usize> {
|
||||
if let Some(pubkey) = pubkey {
|
||||
self.signers
|
||||
.iter()
|
||||
.position(|signer| signer.pubkey() == pubkey)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DefaultSigner {
|
||||
|
@@ -23,6 +23,7 @@ impl std::fmt::Debug for DisplayError {
|
||||
}
|
||||
}
|
||||
|
||||
pub mod commitment;
|
||||
pub mod fee_payer;
|
||||
pub mod input_parsers;
|
||||
pub mod input_validators;
|
||||
|
@@ -47,32 +47,14 @@ fn signer_arg<'a, 'b>() -> Arg<'a, 'b> {
|
||||
.help(SIGNER_ARG.help)
|
||||
}
|
||||
|
||||
pub trait ArgsConfig {
|
||||
fn blockhash_arg<'a, 'b>(&self, arg: Arg<'a, 'b>) -> Arg<'a, 'b> {
|
||||
arg
|
||||
}
|
||||
fn sign_only_arg<'a, 'b>(&self, arg: Arg<'a, 'b>) -> Arg<'a, 'b> {
|
||||
arg
|
||||
}
|
||||
fn signer_arg<'a, 'b>(&self, arg: Arg<'a, 'b>) -> Arg<'a, 'b> {
|
||||
arg
|
||||
}
|
||||
}
|
||||
|
||||
pub trait OfflineArgs {
|
||||
fn offline_args(self) -> Self;
|
||||
fn offline_args_config(self, config: &dyn ArgsConfig) -> Self;
|
||||
fn offline_args(self, global: bool) -> Self;
|
||||
}
|
||||
|
||||
impl OfflineArgs for App<'_, '_> {
|
||||
fn offline_args_config(self, config: &dyn ArgsConfig) -> Self {
|
||||
self.arg(config.blockhash_arg(blockhash_arg()))
|
||||
.arg(config.sign_only_arg(sign_only_arg()))
|
||||
.arg(config.signer_arg(signer_arg()))
|
||||
}
|
||||
fn offline_args(self) -> Self {
|
||||
struct NullArgsConfig {}
|
||||
impl ArgsConfig for NullArgsConfig {}
|
||||
self.offline_args_config(&NullArgsConfig {})
|
||||
fn offline_args(self, global: bool) -> Self {
|
||||
self.arg(blockhash_arg().global(global))
|
||||
.arg(sign_only_arg().global(global))
|
||||
.arg(signer_arg().global(global))
|
||||
}
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-cli-config"
|
||||
description = "Blockchain, Rebuilt for Scale"
|
||||
version = "1.4.26"
|
||||
version = "1.3.24"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
|
@@ -17,10 +17,9 @@ pub struct Config {
|
||||
pub json_rpc_url: String,
|
||||
pub websocket_url: String,
|
||||
pub keypair_path: String,
|
||||
|
||||
#[serde(default)]
|
||||
pub address_labels: HashMap<String, String>,
|
||||
#[serde(default)]
|
||||
pub commitment: String,
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
@@ -42,14 +41,11 @@ impl Default for Config {
|
||||
"System Program".to_string(),
|
||||
);
|
||||
|
||||
let commitment = "singleGossip".to_string();
|
||||
|
||||
Self {
|
||||
json_rpc_url,
|
||||
websocket_url,
|
||||
keypair_path,
|
||||
address_labels,
|
||||
commitment,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -80,6 +76,17 @@ impl Config {
|
||||
ws_url.to_string()
|
||||
}
|
||||
|
||||
pub fn compute_rpc_banks_url(json_rpc_url: &str) -> String {
|
||||
let json_rpc_url: Option<Url> = json_rpc_url.parse().ok();
|
||||
if json_rpc_url.is_none() {
|
||||
return "".to_string();
|
||||
}
|
||||
let mut url = json_rpc_url.unwrap();
|
||||
let port = url.port().unwrap_or(8899);
|
||||
url.set_port(Some(port + 3)).expect("unable to set port");
|
||||
url.to_string()
|
||||
}
|
||||
|
||||
pub fn import_address_labels<P>(&mut self, filename: P) -> Result<(), io::Error>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
@@ -126,4 +133,28 @@ mod test {
|
||||
|
||||
assert_eq!(Config::compute_websocket_url(&"garbage"), String::new());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compute_rpc_banks_url() {
|
||||
assert_eq!(
|
||||
Config::compute_rpc_banks_url(&"http://devnet.solana.com"),
|
||||
"http://devnet.solana.com:8902/".to_string()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
Config::compute_rpc_banks_url(&"https://devnet.solana.com"),
|
||||
"https://devnet.solana.com:8902/".to_string()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
Config::compute_rpc_banks_url(&"http://example.com:8899"),
|
||||
"http://example.com:8902/".to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
Config::compute_rpc_banks_url(&"https://example.com:1234"),
|
||||
"https://example.com:1237/".to_string()
|
||||
);
|
||||
|
||||
assert_eq!(Config::compute_rpc_banks_url(&"garbage"), String::new());
|
||||
}
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-cli-output"
|
||||
description = "Blockchain, Rebuilt for Scale"
|
||||
version = "1.4.26"
|
||||
version = "1.3.24"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -17,13 +17,13 @@ indicatif = "0.15.0"
|
||||
serde = "1.0.112"
|
||||
serde_derive = "1.0.103"
|
||||
serde_json = "1.0.56"
|
||||
solana-account-decoder = { path = "../account-decoder", version = "1.4.26" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.4.26" }
|
||||
solana-client = { path = "../client", version = "1.4.26" }
|
||||
solana-sdk = { path = "../sdk", version = "1.4.26" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "1.4.26" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "1.4.26" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "1.4.26" }
|
||||
solana-account-decoder = { path = "../account-decoder", version = "1.3.24" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.3.24" }
|
||||
solana-client = { path = "../client", version = "1.3.24" }
|
||||
solana-sdk = { path = "../sdk", version = "1.3.24" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "1.3.24" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "1.3.24" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "1.3.24" }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
@@ -1,8 +1,5 @@
|
||||
use crate::{
|
||||
display::{
|
||||
build_balance_message, build_balance_message_with_config, format_labeled_address,
|
||||
writeln_name_value, BuildBalanceMessageConfig,
|
||||
},
|
||||
display::{build_balance_message, format_labeled_address, writeln_name_value},
|
||||
QuietDisplay, VerboseDisplay,
|
||||
};
|
||||
use chrono::{DateTime, NaiveDateTime, SecondsFormat, Utc};
|
||||
@@ -13,8 +10,7 @@ use serde_json::{Map, Value};
|
||||
use solana_account_decoder::parse_token::UiTokenAccount;
|
||||
use solana_clap_utils::keypair::SignOnly;
|
||||
use solana_client::rpc_response::{
|
||||
RpcAccountBalance, RpcInflationGovernor, RpcInflationRate, RpcKeyedAccount, RpcSupply,
|
||||
RpcVoteAccountInfo,
|
||||
RpcAccountBalance, RpcKeyedAccount, RpcSupply, RpcVoteAccountInfo,
|
||||
};
|
||||
use solana_sdk::{
|
||||
clock::{self, Epoch, Slot, UnixTimestamp},
|
||||
@@ -136,7 +132,7 @@ impl fmt::Display for CliBlockProduction {
|
||||
"{}",
|
||||
style(format!(
|
||||
" {:<44} {:>15} {:>15} {:>15} {:>23}",
|
||||
"Identity",
|
||||
"Identity Pubkey",
|
||||
"Leader Slots",
|
||||
"Blocks Produced",
|
||||
"Skipped Slots",
|
||||
@@ -245,9 +241,6 @@ impl fmt::Display for CliEpochInfo {
|
||||
)?;
|
||||
writeln_name_value(f, "Slot:", &self.epoch_info.absolute_slot.to_string())?;
|
||||
writeln_name_value(f, "Epoch:", &self.epoch_info.epoch.to_string())?;
|
||||
if let Some(transaction_count) = &self.epoch_info.transaction_count {
|
||||
writeln_name_value(f, "Transaction Count:", &transaction_count.to_string())?;
|
||||
}
|
||||
let start_slot = self.epoch_info.absolute_slot - self.epoch_info.slot_index;
|
||||
let end_slot = start_slot + self.epoch_info.slots_in_epoch;
|
||||
writeln_name_value(
|
||||
@@ -362,42 +355,6 @@ impl fmt::Display for CliValidators {
|
||||
},
|
||||
)
|
||||
}
|
||||
writeln!(
|
||||
f,
|
||||
"{}",
|
||||
style(format!(
|
||||
" {:<44} {:<38} {} {} {} {:>10} {:^8} {}",
|
||||
"Identity",
|
||||
"Vote Account",
|
||||
"Commission",
|
||||
"Last Vote",
|
||||
"Root Block",
|
||||
"Credits",
|
||||
"Version",
|
||||
"Active Stake",
|
||||
))
|
||||
.bold()
|
||||
)?;
|
||||
for validator in &self.current_validators {
|
||||
write_vote_account(
|
||||
f,
|
||||
validator,
|
||||
self.total_active_stake,
|
||||
self.use_lamports_unit,
|
||||
false,
|
||||
)?;
|
||||
}
|
||||
for validator in &self.delinquent_validators {
|
||||
write_vote_account(
|
||||
f,
|
||||
validator,
|
||||
self.total_active_stake,
|
||||
self.use_lamports_unit,
|
||||
true,
|
||||
)?;
|
||||
}
|
||||
|
||||
writeln!(f)?;
|
||||
writeln_name_value(
|
||||
f,
|
||||
"Active Stake:",
|
||||
@@ -449,6 +406,41 @@ impl fmt::Display for CliValidators {
|
||||
)?;
|
||||
}
|
||||
|
||||
writeln!(f)?;
|
||||
writeln!(
|
||||
f,
|
||||
"{}",
|
||||
style(format!(
|
||||
" {:<44} {:<38} {} {} {} {:>10} {:^8} {}",
|
||||
"Identity Pubkey",
|
||||
"Vote Account Pubkey",
|
||||
"Commission",
|
||||
"Last Vote",
|
||||
"Root Block",
|
||||
"Credits",
|
||||
"Version",
|
||||
"Active Stake",
|
||||
))
|
||||
.bold()
|
||||
)?;
|
||||
for validator in &self.current_validators {
|
||||
write_vote_account(
|
||||
f,
|
||||
validator,
|
||||
self.total_active_stake,
|
||||
self.use_lamports_unit,
|
||||
false,
|
||||
)?;
|
||||
}
|
||||
for validator in &self.delinquent_validators {
|
||||
write_vote_account(
|
||||
f,
|
||||
validator,
|
||||
self.total_active_stake,
|
||||
self.use_lamports_unit,
|
||||
true,
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -528,7 +520,7 @@ impl fmt::Display for CliNonceAccount {
|
||||
)
|
||||
)?;
|
||||
let nonce = self.nonce.as_deref().unwrap_or("uninitialized");
|
||||
writeln!(f, "Nonce blockhash: {}", nonce)?;
|
||||
writeln!(f, "Nonce: {}", nonce)?;
|
||||
if let Some(fees) = self.lamports_per_signature {
|
||||
writeln!(f, "Fee: {} lamports per signature", fees)?;
|
||||
} else {
|
||||
@@ -549,15 +541,7 @@ impl CliStakeVec {
|
||||
}
|
||||
|
||||
impl QuietDisplay for CliStakeVec {}
|
||||
impl VerboseDisplay for CliStakeVec {
|
||||
fn write_str(&self, w: &mut dyn std::fmt::Write) -> std::fmt::Result {
|
||||
for state in &self.0 {
|
||||
writeln!(w)?;
|
||||
VerboseDisplay::write_str(state, w)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
impl VerboseDisplay for CliStakeVec {}
|
||||
|
||||
impl fmt::Display for CliStakeVec {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
@@ -578,12 +562,7 @@ pub struct CliKeyedStakeState {
|
||||
}
|
||||
|
||||
impl QuietDisplay for CliKeyedStakeState {}
|
||||
impl VerboseDisplay for CliKeyedStakeState {
|
||||
fn write_str(&self, w: &mut dyn std::fmt::Write) -> std::fmt::Result {
|
||||
writeln!(w, "Stake Pubkey: {}", self.stake_pubkey)?;
|
||||
VerboseDisplay::write_str(&self.stake_state, w)
|
||||
}
|
||||
}
|
||||
impl VerboseDisplay for CliKeyedStakeState {}
|
||||
|
||||
impl fmt::Display for CliKeyedStakeState {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
@@ -600,7 +579,7 @@ pub struct CliEpochReward {
|
||||
pub amount: u64, // lamports
|
||||
pub post_balance: u64, // lamports
|
||||
pub percent_change: f64,
|
||||
pub apr: Option<f64>,
|
||||
pub apr: f64,
|
||||
}
|
||||
|
||||
fn show_epoch_rewards(
|
||||
@@ -615,22 +594,19 @@ fn show_epoch_rewards(
|
||||
writeln!(f, "Epoch Rewards:")?;
|
||||
writeln!(
|
||||
f,
|
||||
" {:<6} {:<11} {:<16} {:<16} {:>14} {:>14}",
|
||||
" {:<8} {:<11} {:<15} {:<15} {:>14} {:>14}",
|
||||
"Epoch", "Reward Slot", "Amount", "New Balance", "Percent Change", "APR"
|
||||
)?;
|
||||
for reward in epoch_rewards {
|
||||
writeln!(
|
||||
f,
|
||||
" {:<6} {:<11} ◎{:<16.9} ◎{:<14.9} {:>13.2}% {}",
|
||||
" {:<8} {:<11} ◎{:<14.9} ◎{:<14.9} {:>13.9}% {:>13.9}%",
|
||||
reward.epoch,
|
||||
reward.effective_slot,
|
||||
lamports_to_sol(reward.amount),
|
||||
lamports_to_sol(reward.post_balance),
|
||||
reward.percent_change,
|
||||
reward
|
||||
.apr
|
||||
.map(|apr| format!("{:>13.2}%", apr))
|
||||
.unwrap_or_default(),
|
||||
reward.apr,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
@@ -643,8 +619,6 @@ pub struct CliStakeState {
|
||||
pub stake_type: CliStakeType,
|
||||
pub account_balance: u64,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub credits_observed: Option<u64>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub delegated_stake: Option<u64>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub delegated_vote_account_address: Option<String>,
|
||||
@@ -673,15 +647,7 @@ pub struct CliStakeState {
|
||||
}
|
||||
|
||||
impl QuietDisplay for CliStakeState {}
|
||||
impl VerboseDisplay for CliStakeState {
|
||||
fn write_str(&self, w: &mut dyn std::fmt::Write) -> std::fmt::Result {
|
||||
write!(w, "{}", self)?;
|
||||
if let Some(credits) = self.credits_observed {
|
||||
writeln!(w, "Credits Observed: {}", credits)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
impl VerboseDisplay for CliStakeState {}
|
||||
|
||||
impl fmt::Display for CliStakeState {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
@@ -870,19 +836,14 @@ impl fmt::Display for CliStakeHistory {
|
||||
))
|
||||
.bold()
|
||||
)?;
|
||||
let config = BuildBalanceMessageConfig {
|
||||
use_lamports_unit: self.use_lamports_unit,
|
||||
show_unit: false,
|
||||
trim_trailing_zeros: false,
|
||||
};
|
||||
for entry in &self.entries {
|
||||
writeln!(
|
||||
f,
|
||||
" {:>5} {:>20} {:>20} {:>20} {}",
|
||||
entry.epoch,
|
||||
build_balance_message_with_config(entry.effective_stake, &config),
|
||||
build_balance_message_with_config(entry.activating_stake, &config),
|
||||
build_balance_message_with_config(entry.deactivating_stake, &config),
|
||||
build_balance_message(entry.effective_stake, self.use_lamports_unit, false),
|
||||
build_balance_message(entry.activating_stake, self.use_lamports_unit, false),
|
||||
build_balance_message(entry.deactivating_stake, self.use_lamports_unit, false),
|
||||
if self.use_lamports_unit {
|
||||
"lamports"
|
||||
} else {
|
||||
@@ -986,8 +947,8 @@ impl VerboseDisplay for CliValidatorInfo {}
|
||||
|
||||
impl fmt::Display for CliValidatorInfo {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
writeln_name_value(f, "Validator Identity:", &self.identity_pubkey)?;
|
||||
writeln_name_value(f, " Info Address:", &self.info_pubkey)?;
|
||||
writeln_name_value(f, "Validator Identity Pubkey:", &self.identity_pubkey)?;
|
||||
writeln_name_value(f, " Info Pubkey:", &self.info_pubkey)?;
|
||||
for (key, value) in self.info.iter() {
|
||||
writeln_name_value(
|
||||
f,
|
||||
@@ -1151,104 +1112,6 @@ impl fmt::Display for CliBlockTime {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CliLeaderSchedule {
|
||||
pub epoch: Epoch,
|
||||
pub leader_schedule_entries: Vec<CliLeaderScheduleEntry>,
|
||||
}
|
||||
|
||||
impl QuietDisplay for CliLeaderSchedule {}
|
||||
impl VerboseDisplay for CliLeaderSchedule {}
|
||||
|
||||
impl fmt::Display for CliLeaderSchedule {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
for entry in &self.leader_schedule_entries {
|
||||
writeln!(f, " {:<15} {:<44}", entry.slot, entry.leader)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CliLeaderScheduleEntry {
|
||||
pub slot: Slot,
|
||||
pub leader: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CliInflation {
|
||||
pub governor: RpcInflationGovernor,
|
||||
pub current_rate: RpcInflationRate,
|
||||
}
|
||||
|
||||
impl QuietDisplay for CliInflation {}
|
||||
impl VerboseDisplay for CliInflation {}
|
||||
|
||||
impl fmt::Display for CliInflation {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
writeln!(f, "{}", style("Inflation Governor:").bold())?;
|
||||
if (self.governor.initial - self.governor.terminal).abs() < f64::EPSILON {
|
||||
writeln!(
|
||||
f,
|
||||
"Fixed APR: {:>5.2}%",
|
||||
self.governor.terminal * 100.
|
||||
)?;
|
||||
} else {
|
||||
writeln!(
|
||||
f,
|
||||
"Initial APR: {:>5.2}%",
|
||||
self.governor.initial * 100.
|
||||
)?;
|
||||
writeln!(
|
||||
f,
|
||||
"Terminal APR: {:>5.2}%",
|
||||
self.governor.terminal * 100.
|
||||
)?;
|
||||
writeln!(
|
||||
f,
|
||||
"Rate reduction per year: {:>5.2}%",
|
||||
self.governor.taper * 100.
|
||||
)?;
|
||||
}
|
||||
if self.governor.foundation_term > 0. {
|
||||
writeln!(
|
||||
f,
|
||||
"Foundation percentage: {:>5.2}%",
|
||||
self.governor.foundation
|
||||
)?;
|
||||
writeln!(
|
||||
f,
|
||||
"Foundation term: {:.1} years",
|
||||
self.governor.foundation_term
|
||||
)?;
|
||||
}
|
||||
|
||||
writeln!(
|
||||
f,
|
||||
"\n{}",
|
||||
style(format!("Inflation for Epoch {}:", self.current_rate.epoch)).bold()
|
||||
)?;
|
||||
writeln!(
|
||||
f,
|
||||
"Total APR: {:>5.2}%",
|
||||
self.current_rate.total * 100.
|
||||
)?;
|
||||
writeln!(
|
||||
f,
|
||||
"Staking APR: {:>5.2}%",
|
||||
self.current_rate.validator * 100.
|
||||
)?;
|
||||
writeln!(
|
||||
f,
|
||||
"Foundation APR: {:>5.2}%",
|
||||
self.current_rate.foundation * 100.
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CliSignOnlyData {
|
||||
@@ -1540,37 +1403,6 @@ pub fn parse_sign_only_reply_string(reply: &str) -> SignOnly {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum CliSignatureVerificationStatus {
|
||||
None,
|
||||
Pass,
|
||||
Fail,
|
||||
}
|
||||
|
||||
impl CliSignatureVerificationStatus {
|
||||
pub fn verify_transaction(tx: &Transaction) -> Vec<Self> {
|
||||
tx.verify_with_results()
|
||||
.iter()
|
||||
.zip(&tx.signatures)
|
||||
.map(|(stat, sig)| match stat {
|
||||
true => CliSignatureVerificationStatus::Pass,
|
||||
false if sig == &Signature::default() => CliSignatureVerificationStatus::None,
|
||||
false => CliSignatureVerificationStatus::Fail,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for CliSignatureVerificationStatus {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::None => write!(f, "none"),
|
||||
Self::Pass => write!(f, "pass"),
|
||||
Self::Fail => write!(f, "fail"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@@ -1,4 +1,3 @@
|
||||
use crate::cli_output::CliSignatureVerificationStatus;
|
||||
use console::style;
|
||||
use indicatif::{ProgressBar, ProgressStyle};
|
||||
use solana_sdk::{
|
||||
@@ -8,63 +7,22 @@ use solana_sdk::{
|
||||
use solana_transaction_status::UiTransactionStatusMeta;
|
||||
use std::{collections::HashMap, fmt, io};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct BuildBalanceMessageConfig {
|
||||
pub use_lamports_unit: bool,
|
||||
pub show_unit: bool,
|
||||
pub trim_trailing_zeros: bool,
|
||||
}
|
||||
|
||||
impl Default for BuildBalanceMessageConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
use_lamports_unit: false,
|
||||
show_unit: true,
|
||||
trim_trailing_zeros: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build_balance_message_with_config(
|
||||
lamports: u64,
|
||||
config: &BuildBalanceMessageConfig,
|
||||
) -> String {
|
||||
let value = if config.use_lamports_unit {
|
||||
lamports.to_string()
|
||||
pub fn build_balance_message(lamports: u64, use_lamports_unit: bool, show_unit: bool) -> String {
|
||||
if use_lamports_unit {
|
||||
let ess = if lamports == 1 { "" } else { "s" };
|
||||
let unit = if show_unit {
|
||||
format!(" lamport{}", ess)
|
||||
} else {
|
||||
"".to_string()
|
||||
};
|
||||
format!("{:?}{}", lamports, unit)
|
||||
} else {
|
||||
let sol = lamports_to_sol(lamports);
|
||||
let sol_str = format!("{:.9}", sol);
|
||||
if config.trim_trailing_zeros {
|
||||
sol_str
|
||||
.trim_end_matches('0')
|
||||
.trim_end_matches('.')
|
||||
.to_string()
|
||||
} else {
|
||||
sol_str
|
||||
}
|
||||
};
|
||||
let unit = if config.show_unit {
|
||||
if config.use_lamports_unit {
|
||||
let ess = if lamports == 1 { "" } else { "s" };
|
||||
format!(" lamport{}", ess)
|
||||
} else {
|
||||
" SOL".to_string()
|
||||
}
|
||||
} else {
|
||||
"".to_string()
|
||||
};
|
||||
format!("{}{}", value, unit)
|
||||
}
|
||||
|
||||
pub fn build_balance_message(lamports: u64, use_lamports_unit: bool, show_unit: bool) -> String {
|
||||
build_balance_message_with_config(
|
||||
lamports,
|
||||
&BuildBalanceMessageConfig {
|
||||
use_lamports_unit,
|
||||
show_unit,
|
||||
..BuildBalanceMessageConfig::default()
|
||||
},
|
||||
)
|
||||
let pretty_sol = sol_str.trim_end_matches('0').trim_end_matches('.');
|
||||
let unit = if show_unit { " SOL" } else { "" };
|
||||
format!("{}{}", pretty_sol, unit)
|
||||
}
|
||||
}
|
||||
|
||||
// Pretty print a "name value"
|
||||
@@ -77,7 +35,7 @@ pub fn println_name_value(name: &str, value: &str) {
|
||||
println!("{} {}", style(name).bold(), styled_value);
|
||||
}
|
||||
|
||||
pub fn writeln_name_value(f: &mut dyn fmt::Write, name: &str, value: &str) -> fmt::Result {
|
||||
pub fn writeln_name_value(f: &mut fmt::Formatter, name: &str, value: &str) -> fmt::Result {
|
||||
let styled_value = if value == "" {
|
||||
style("(not set)").italic()
|
||||
} else {
|
||||
@@ -127,7 +85,6 @@ pub fn write_transaction<W: io::Write>(
|
||||
transaction: &Transaction,
|
||||
transaction_status: &Option<UiTransactionStatusMeta>,
|
||||
prefix: &str,
|
||||
sigverify_status: Option<&[CliSignatureVerificationStatus]>,
|
||||
) -> io::Result<()> {
|
||||
let message = &transaction.message;
|
||||
writeln!(
|
||||
@@ -135,24 +92,11 @@ pub fn write_transaction<W: io::Write>(
|
||||
"{}Recent Blockhash: {:?}",
|
||||
prefix, message.recent_blockhash
|
||||
)?;
|
||||
let sigverify_statuses = if let Some(sigverify_status) = sigverify_status {
|
||||
sigverify_status
|
||||
.iter()
|
||||
.map(|s| format!(" ({})", s))
|
||||
.collect()
|
||||
} else {
|
||||
vec!["".to_string(); transaction.signatures.len()]
|
||||
};
|
||||
for (signature_index, (signature, sigverify_status)) in transaction
|
||||
.signatures
|
||||
.iter()
|
||||
.zip(&sigverify_statuses)
|
||||
.enumerate()
|
||||
{
|
||||
for (signature_index, signature) in transaction.signatures.iter().enumerate() {
|
||||
writeln!(
|
||||
w,
|
||||
"{}Signature {}: {:?}{}",
|
||||
prefix, signature_index, signature, sigverify_status,
|
||||
"{}Signature {}: {:?}",
|
||||
prefix, signature_index, signature
|
||||
)?;
|
||||
}
|
||||
writeln!(w, "{}{:?}", prefix, message.header)?;
|
||||
@@ -273,18 +217,9 @@ pub fn println_transaction(
|
||||
transaction: &Transaction,
|
||||
transaction_status: &Option<UiTransactionStatusMeta>,
|
||||
prefix: &str,
|
||||
sigverify_status: Option<&[CliSignatureVerificationStatus]>,
|
||||
) {
|
||||
let mut w = Vec::new();
|
||||
if write_transaction(
|
||||
&mut w,
|
||||
transaction,
|
||||
transaction_status,
|
||||
prefix,
|
||||
sigverify_status,
|
||||
)
|
||||
.is_ok()
|
||||
{
|
||||
if write_transaction(&mut w, transaction, transaction_status, prefix).is_ok() {
|
||||
if let Ok(s) = String::from_utf8(w) {
|
||||
print!("{}", s);
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-cli"
|
||||
description = "Blockchain, Rebuilt for Scale"
|
||||
version = "1.4.26"
|
||||
version = "1.3.24"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -23,34 +23,37 @@ indicatif = "0.15.0"
|
||||
humantime = "2.0.1"
|
||||
num-traits = "0.2"
|
||||
pretty-hex = "0.1.1"
|
||||
reqwest = { version = "0.10.8", default-features = false, features = ["blocking", "rustls-tls", "json"] }
|
||||
reqwest = { version = "0.10.6", default-features = false, features = ["blocking", "rustls-tls", "json"] }
|
||||
serde = "1.0.112"
|
||||
serde_derive = "1.0.103"
|
||||
serde_json = "1.0.56"
|
||||
solana-account-decoder = { path = "../account-decoder", version = "1.4.26" }
|
||||
solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "1.4.26" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.4.26" }
|
||||
solana-cli-config = { path = "../cli-config", version = "1.4.26" }
|
||||
solana-cli-output = { path = "../cli-output", version = "1.4.26" }
|
||||
solana-client = { path = "../client", version = "1.4.26" }
|
||||
solana-config-program = { path = "../programs/config", version = "1.4.26" }
|
||||
solana-faucet = { path = "../faucet", version = "1.4.26" }
|
||||
solana-logger = { path = "../logger", version = "1.4.26" }
|
||||
solana-net-utils = { path = "../net-utils", version = "1.4.26" }
|
||||
solana-account-decoder = { path = "../account-decoder", version = "1.3.24" }
|
||||
solana-budget-program = { path = "../programs/budget", version = "1.3.24" }
|
||||
solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "1.3.24" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.3.24" }
|
||||
solana-cli-config = { path = "../cli-config", version = "1.3.24" }
|
||||
solana-cli-output = { path = "../cli-output", version = "1.3.24" }
|
||||
solana-client = { path = "../client", version = "1.3.24" }
|
||||
solana-config-program = { path = "../programs/config", version = "1.3.24" }
|
||||
solana-faucet = { path = "../faucet", version = "1.3.24" }
|
||||
solana-logger = { path = "../logger", version = "1.3.24" }
|
||||
solana-net-utils = { path = "../net-utils", version = "1.3.24" }
|
||||
solana_rbpf = "=0.1.34"
|
||||
solana-remote-wallet = { path = "../remote-wallet", version = "1.4.26" }
|
||||
solana-sdk = { path = "../sdk", version = "1.4.26" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "1.4.26" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "1.4.26" }
|
||||
solana-version = { path = "../version", version = "1.4.26" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "1.4.26" }
|
||||
solana-vote-signer = { path = "../vote-signer", version = "1.4.26" }
|
||||
solana-remote-wallet = { path = "../remote-wallet", version = "1.3.24" }
|
||||
solana-runtime = { path = "../runtime", version = "1.3.24" }
|
||||
solana-sdk = { path = "../sdk", version = "1.3.24" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "1.3.24" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "1.3.24" }
|
||||
solana-version = { path = "../version", version = "1.3.24" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "1.3.24" }
|
||||
solana-vote-signer = { path = "../vote-signer", version = "1.3.24" }
|
||||
thiserror = "1.0.20"
|
||||
tiny-bip39 = "0.7.0"
|
||||
url = "2.1.1"
|
||||
|
||||
[dev-dependencies]
|
||||
solana-core = { path = "../core", version = "1.4.26" }
|
||||
solana-core = { path = "../core", version = "1.3.24" }
|
||||
solana-budget-program = { path = "../programs/budget", version = "1.3.24" }
|
||||
tempfile = "3.1.0"
|
||||
|
||||
[[bin]]
|
||||
|
1582
cli/src/cli.rs
1582
cli/src/cli.rs
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -9,13 +9,12 @@ use solana_clap_utils::{input_parsers::*, input_validators::*, keypair::*};
|
||||
use solana_cli_output::{QuietDisplay, VerboseDisplay};
|
||||
use solana_client::{client_error::ClientError, rpc_client::RpcClient};
|
||||
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
|
||||
use solana_sdk::{
|
||||
clock::Slot,
|
||||
use solana_runtime::{
|
||||
feature::{self, Feature},
|
||||
feature_set::FEATURE_NAMES,
|
||||
message::Message,
|
||||
pubkey::Pubkey,
|
||||
transaction::Transaction,
|
||||
};
|
||||
use solana_sdk::{
|
||||
clock::Slot, message::Message, pubkey::Pubkey, system_instruction, transaction::Transaction,
|
||||
};
|
||||
use std::{collections::HashMap, fmt, sync::Arc};
|
||||
|
||||
@@ -242,22 +241,7 @@ fn feature_activation_allowed(rpc_client: &RpcClient, quiet: bool) -> Result<boo
|
||||
.unwrap_or(false);
|
||||
|
||||
if !feature_activation_allowed && !quiet {
|
||||
if active_stake_by_feature_set.get(&my_feature_set).is_none() {
|
||||
println!(
|
||||
"{}",
|
||||
style("To activate features the tool and cluster feature sets must match, select a tool version that matches the cluster")
|
||||
.bold());
|
||||
} else {
|
||||
println!(
|
||||
"{}",
|
||||
style("To activate features the stake must be >= 95%").bold()
|
||||
);
|
||||
}
|
||||
println!(
|
||||
"{}",
|
||||
style(format!("Tool Feture Set: {}", my_feature_set)).bold()
|
||||
);
|
||||
println!("{}", style("Cluster Feature Sets and Stakes:").bold());
|
||||
println!("{}", style("Stake By Feature Set:").bold());
|
||||
for (feature_set, percentage) in active_stake_by_feature_set.iter() {
|
||||
if *feature_set == 0 {
|
||||
println!("unknown - {}%", percentage);
|
||||
@@ -295,7 +279,7 @@ fn process_status(
|
||||
let feature_id = &feature_ids[i];
|
||||
let feature_name = FEATURE_NAMES.get(feature_id).unwrap();
|
||||
if let Some(account) = account {
|
||||
if let Some(feature) = feature::from_account(&account) {
|
||||
if let Some(feature) = Feature::from_account(&account) {
|
||||
let feature_status = match feature.activated_at {
|
||||
None => CliFeatureStatus::Pending,
|
||||
Some(activation_slot) => CliFeatureStatus::Active(activation_slot),
|
||||
@@ -336,7 +320,7 @@ fn process_activate(
|
||||
.next()
|
||||
.unwrap();
|
||||
if let Some(account) = account {
|
||||
if feature::from_account(&account).is_some() {
|
||||
if Feature::from_account(&account).is_some() {
|
||||
return Err(format!("{} has already been activated", feature_id).into());
|
||||
}
|
||||
}
|
||||
@@ -356,11 +340,15 @@ fn process_activate(
|
||||
&config.signers[0].pubkey(),
|
||||
|lamports| {
|
||||
Message::new(
|
||||
&feature::activate_with_lamports(
|
||||
&feature_id,
|
||||
&config.signers[0].pubkey(),
|
||||
lamports,
|
||||
),
|
||||
&[
|
||||
system_instruction::transfer(
|
||||
&config.signers[0].pubkey(),
|
||||
&feature_id,
|
||||
lamports,
|
||||
),
|
||||
system_instruction::allocate(&feature_id, Feature::size_of() as u64),
|
||||
system_instruction::assign(&feature_id, &feature::id()),
|
||||
],
|
||||
Some(&config.signers[0].pubkey()),
|
||||
)
|
||||
},
|
||||
|
@@ -1,7 +1,7 @@
|
||||
use crate::cli::{CliCommand, CliCommandInfo, CliConfig, CliError, ProcessResult};
|
||||
use clap::{App, ArgMatches, SubCommand};
|
||||
use console::style;
|
||||
use solana_clap_utils::keypair::*;
|
||||
use solana_cli_output::CliInflation;
|
||||
use solana_client::rpc_client::RpcClient;
|
||||
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
|
||||
use std::sync::Arc;
|
||||
@@ -34,18 +34,56 @@ pub fn parse_inflation_subcommand(
|
||||
|
||||
pub fn process_inflation_subcommand(
|
||||
rpc_client: &RpcClient,
|
||||
config: &CliConfig,
|
||||
_config: &CliConfig,
|
||||
inflation_subcommand: &InflationCliCommand,
|
||||
) -> ProcessResult {
|
||||
assert_eq!(*inflation_subcommand, InflationCliCommand::Show);
|
||||
|
||||
let governor = rpc_client.get_inflation_governor()?;
|
||||
let current_rate = rpc_client.get_inflation_rate()?;
|
||||
let current_inflation_rate = rpc_client.get_inflation_rate()?;
|
||||
|
||||
let inflation = CliInflation {
|
||||
governor,
|
||||
current_rate,
|
||||
};
|
||||
println!("{}", style("Inflation Governor:").bold());
|
||||
if (governor.initial - governor.terminal).abs() < f64::EPSILON {
|
||||
println!(
|
||||
"Fixed APR: {:>5.2}%",
|
||||
governor.terminal * 100.
|
||||
);
|
||||
} else {
|
||||
println!("Initial APR: {:>5.2}%", governor.initial * 100.);
|
||||
println!(
|
||||
"Terminal APR: {:>5.2}%",
|
||||
governor.terminal * 100.
|
||||
);
|
||||
println!("Rate reduction per year: {:>5.2}%", governor.taper * 100.);
|
||||
}
|
||||
if governor.foundation_term > 0. {
|
||||
println!("Foundation percentage: {:>5.2}%", governor.foundation);
|
||||
println!(
|
||||
"Foundation term: {:.1} years",
|
||||
governor.foundation_term
|
||||
);
|
||||
}
|
||||
|
||||
Ok(config.output_format.formatted_string(&inflation))
|
||||
println!(
|
||||
"\n{}",
|
||||
style(format!(
|
||||
"Inflation for Epoch {}:",
|
||||
current_inflation_rate.epoch
|
||||
))
|
||||
.bold()
|
||||
);
|
||||
println!(
|
||||
"Total APR: {:>5.2}%",
|
||||
current_inflation_rate.total * 100.
|
||||
);
|
||||
println!(
|
||||
"Staking APR: {:>5.2}%",
|
||||
current_inflation_rate.validator * 100.
|
||||
);
|
||||
println!(
|
||||
"Foundation APR: {:>5.2}%",
|
||||
current_inflation_rate.foundation * 100.
|
||||
);
|
||||
|
||||
Ok("".to_string())
|
||||
}
|
||||
|
@@ -26,7 +26,6 @@ pub mod cluster_query;
|
||||
pub mod feature;
|
||||
pub mod inflation;
|
||||
pub mod nonce;
|
||||
pub mod program;
|
||||
pub mod send_tpu;
|
||||
pub mod spend_utils;
|
||||
pub mod stake;
|
||||
|
@@ -3,8 +3,11 @@ use clap::{
|
||||
SubCommand,
|
||||
};
|
||||
use console::style;
|
||||
|
||||
use solana_clap_utils::{
|
||||
input_validators::{is_url, is_url_or_moniker, normalize_to_url_if_moniker},
|
||||
commitment::COMMITMENT_ARG,
|
||||
input_parsers::commitment_of,
|
||||
input_validators::is_url,
|
||||
keypair::{CliSigners, DefaultSigner, SKIP_SEED_PHRASE_VALIDATION_ARG},
|
||||
DisplayError,
|
||||
};
|
||||
@@ -60,19 +63,12 @@ fn parse_settings(matches: &ArgMatches<'_>) -> Result<bool, Box<dyn error::Error
|
||||
);
|
||||
let (keypair_setting_type, keypair_path) =
|
||||
CliConfig::compute_keypair_path_setting("", &config.keypair_path);
|
||||
let (commitment_setting_type, commitment) =
|
||||
CliConfig::compute_commitment_config("", &config.commitment);
|
||||
|
||||
if let Some(field) = subcommand_matches.value_of("specific_setting") {
|
||||
let (field_name, value, setting_type) = match field {
|
||||
"json_rpc_url" => ("RPC URL", json_rpc_url, url_setting_type),
|
||||
"websocket_url" => ("WebSocket URL", websocket_url, ws_setting_type),
|
||||
"keypair" => ("Key Path", keypair_path, keypair_setting_type),
|
||||
"commitment" => (
|
||||
"Commitment",
|
||||
commitment.commitment.to_string(),
|
||||
commitment_setting_type,
|
||||
),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
println_name_value_or(&format!("{}:", field_name), &value, setting_type);
|
||||
@@ -81,16 +77,11 @@ fn parse_settings(matches: &ArgMatches<'_>) -> Result<bool, Box<dyn error::Error
|
||||
println_name_value_or("RPC URL:", &json_rpc_url, url_setting_type);
|
||||
println_name_value_or("WebSocket URL:", &websocket_url, ws_setting_type);
|
||||
println_name_value_or("Keypair Path:", &keypair_path, keypair_setting_type);
|
||||
println_name_value_or(
|
||||
"Commitment:",
|
||||
&commitment.commitment.to_string(),
|
||||
commitment_setting_type,
|
||||
);
|
||||
}
|
||||
}
|
||||
("set", Some(subcommand_matches)) => {
|
||||
if let Some(url) = subcommand_matches.value_of("json_rpc_url") {
|
||||
config.json_rpc_url = normalize_to_url_if_moniker(url);
|
||||
config.json_rpc_url = url.to_string();
|
||||
// Revert to a computed `websocket_url` value when `json_rpc_url` is
|
||||
// changed
|
||||
config.websocket_url = "".to_string();
|
||||
@@ -101,9 +92,6 @@ fn parse_settings(matches: &ArgMatches<'_>) -> Result<bool, Box<dyn error::Error
|
||||
if let Some(keypair) = subcommand_matches.value_of("keypair") {
|
||||
config.keypair_path = keypair.to_string();
|
||||
}
|
||||
if let Some(commitment) = subcommand_matches.value_of("commitment") {
|
||||
config.commitment = commitment.to_string();
|
||||
}
|
||||
|
||||
config.save(config_file)?;
|
||||
|
||||
@@ -117,18 +105,11 @@ fn parse_settings(matches: &ArgMatches<'_>) -> Result<bool, Box<dyn error::Error
|
||||
);
|
||||
let (keypair_setting_type, keypair_path) =
|
||||
CliConfig::compute_keypair_path_setting("", &config.keypair_path);
|
||||
let (commitment_setting_type, commitment) =
|
||||
CliConfig::compute_commitment_config("", &config.commitment);
|
||||
|
||||
println_name_value("Config File:", config_file);
|
||||
println_name_value_or("RPC URL:", &json_rpc_url, url_setting_type);
|
||||
println_name_value_or("WebSocket URL:", &websocket_url, ws_setting_type);
|
||||
println_name_value_or("Keypair Path:", &keypair_path, keypair_setting_type);
|
||||
println_name_value_or(
|
||||
"Commitment:",
|
||||
&commitment.commitment.to_string(),
|
||||
commitment_setting_type,
|
||||
);
|
||||
}
|
||||
("import-address-labels", Some(subcommand_matches)) => {
|
||||
let filename = value_t_or_exit!(subcommand_matches, "filename", PathBuf);
|
||||
@@ -184,20 +165,9 @@ pub fn parse_args<'a>(
|
||||
path: default_signer_path.clone(),
|
||||
};
|
||||
|
||||
let CliCommandInfo {
|
||||
command,
|
||||
mut signers,
|
||||
} = parse_command(&matches, &default_signer, &mut wallet_manager)?;
|
||||
let CliCommandInfo { command, signers } =
|
||||
parse_command(&matches, &default_signer, &mut wallet_manager)?;
|
||||
|
||||
if signers.is_empty() {
|
||||
if let Ok(signer_info) =
|
||||
default_signer.generate_unique_signers(vec![None], matches, &mut wallet_manager)
|
||||
{
|
||||
signers.extend(signer_info.signers);
|
||||
}
|
||||
}
|
||||
|
||||
let verbose = matches.is_present("verbose");
|
||||
let output_format = matches
|
||||
.value_of("output_format")
|
||||
.map(|value| match value {
|
||||
@@ -205,16 +175,13 @@ pub fn parse_args<'a>(
|
||||
"json-compact" => OutputFormat::JsonCompact,
|
||||
_ => unreachable!(),
|
||||
})
|
||||
.unwrap_or(if verbose {
|
||||
OutputFormat::DisplayVerbose
|
||||
} else {
|
||||
OutputFormat::Display
|
||||
});
|
||||
.unwrap_or(OutputFormat::Display);
|
||||
|
||||
let (_, commitment) = CliConfig::compute_commitment_config(
|
||||
matches.value_of("commitment").unwrap_or(""),
|
||||
&config.commitment,
|
||||
);
|
||||
let commitment = matches
|
||||
.subcommand_name()
|
||||
.and_then(|name| matches.subcommand_matches(name))
|
||||
.and_then(|sub_matches| commitment_of(sub_matches, COMMITMENT_ARG.long))
|
||||
.unwrap_or_default();
|
||||
|
||||
let address_labels = if matches.is_present("no_address_labels") {
|
||||
HashMap::new()
|
||||
@@ -231,7 +198,7 @@ pub fn parse_args<'a>(
|
||||
keypair_path: default_signer_path,
|
||||
rpc_client: None,
|
||||
rpc_timeout,
|
||||
verbose,
|
||||
verbose: matches.is_present("verbose"),
|
||||
output_format,
|
||||
commitment,
|
||||
send_transaction_config: RpcSendTransactionConfig::default(),
|
||||
@@ -242,7 +209,7 @@ pub fn parse_args<'a>(
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn error::Error>> {
|
||||
solana_logger::setup_with_default("off");
|
||||
solana_logger::setup();
|
||||
let matches = app(
|
||||
crate_name!(),
|
||||
crate_description!(),
|
||||
@@ -266,14 +233,11 @@ fn main() -> Result<(), Box<dyn error::Error>> {
|
||||
Arg::with_name("json_rpc_url")
|
||||
.short("u")
|
||||
.long("url")
|
||||
.value_name("URL_OR_MONIKER")
|
||||
.value_name("URL")
|
||||
.takes_value(true)
|
||||
.global(true)
|
||||
.validator(is_url_or_moniker)
|
||||
.help(
|
||||
"URL for Solana's JSON RPC or moniker (or their first letter): \
|
||||
[mainnet-beta, testnet, devnet, localhost]",
|
||||
),
|
||||
.validator(is_url)
|
||||
.help("JSON RPC URL for the solana cluster"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("websocket_url")
|
||||
@@ -293,15 +257,6 @@ fn main() -> Result<(), Box<dyn error::Error>> {
|
||||
.takes_value(true)
|
||||
.help("Filepath or URL to a keypair"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("commitment")
|
||||
.long("commitment")
|
||||
.takes_value(true)
|
||||
.possible_values(&["recent", "single", "singleGossip", "root", "max"])
|
||||
.value_name("COMMITMENT_LEVEL")
|
||||
.global(true)
|
||||
.help("Return information at the selected commitment level"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("verbose")
|
||||
.long("verbose")
|
||||
@@ -353,12 +308,7 @@ fn main() -> Result<(), Box<dyn error::Error>> {
|
||||
.index(1)
|
||||
.value_name("CONFIG_FIELD")
|
||||
.takes_value(true)
|
||||
.possible_values(&[
|
||||
"json_rpc_url",
|
||||
"websocket_url",
|
||||
"keypair",
|
||||
"commitment",
|
||||
])
|
||||
.possible_values(&["json_rpc_url", "websocket_url", "keypair"])
|
||||
.help("Return a specific config setting"),
|
||||
),
|
||||
)
|
||||
@@ -367,7 +317,7 @@ fn main() -> Result<(), Box<dyn error::Error>> {
|
||||
.about("Set a config setting")
|
||||
.group(
|
||||
ArgGroup::with_name("config_settings")
|
||||
.args(&["json_rpc_url", "websocket_url", "keypair", "commitment"])
|
||||
.args(&["json_rpc_url", "websocket_url", "keypair"])
|
||||
.multiple(true)
|
||||
.required(true),
|
||||
),
|
||||
|
@@ -332,7 +332,9 @@ pub fn process_authorize_nonce_account(
|
||||
nonce_authority: SignerIndex,
|
||||
new_authority: &Pubkey,
|
||||
) -> ProcessResult {
|
||||
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
|
||||
let (recent_blockhash, fee_calculator, _) = rpc_client
|
||||
.get_recent_blockhash_with_commitment(config.commitment)?
|
||||
.value;
|
||||
|
||||
let nonce_authority = config.signers[nonce_authority];
|
||||
let ix = authorize_nonce_account(nonce_account, &nonce_authority.pubkey(), new_authority);
|
||||
@@ -347,7 +349,11 @@ pub fn process_authorize_nonce_account(
|
||||
&tx.message,
|
||||
config.commitment,
|
||||
)?;
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner_and_config(
|
||||
&tx,
|
||||
config.commitment,
|
||||
config.send_transaction_config,
|
||||
);
|
||||
log_instruction_custom_error::<NonceError>(result, &config)
|
||||
}
|
||||
|
||||
@@ -394,7 +400,9 @@ pub fn process_create_nonce_account(
|
||||
Message::new(&ixs, Some(&config.signers[0].pubkey()))
|
||||
};
|
||||
|
||||
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
|
||||
let (recent_blockhash, fee_calculator, _) = rpc_client
|
||||
.get_recent_blockhash_with_commitment(config.commitment)?
|
||||
.value;
|
||||
|
||||
let (message, lamports) = resolve_spend_tx_and_check_account_balance(
|
||||
rpc_client,
|
||||
@@ -406,7 +414,9 @@ pub fn process_create_nonce_account(
|
||||
config.commitment,
|
||||
)?;
|
||||
|
||||
if let Ok(nonce_account) = get_account(rpc_client, &nonce_account_address) {
|
||||
if let Ok(nonce_account) =
|
||||
get_account_with_commitment(rpc_client, &nonce_account_address, config.commitment)
|
||||
{
|
||||
let err_msg = if state_from_account(&nonce_account).is_ok() {
|
||||
format!("Nonce account {} already exists", nonce_account_address)
|
||||
} else {
|
||||
@@ -429,7 +439,11 @@ pub fn process_create_nonce_account(
|
||||
|
||||
let mut tx = Transaction::new_unsigned(message);
|
||||
tx.try_sign(&config.signers, recent_blockhash)?;
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner_and_config(
|
||||
&tx,
|
||||
config.commitment,
|
||||
config.send_transaction_config,
|
||||
);
|
||||
log_instruction_custom_error::<SystemError>(result, &config)
|
||||
}
|
||||
|
||||
@@ -457,17 +471,20 @@ pub fn process_new_nonce(
|
||||
(&nonce_account, "nonce_account_pubkey".to_string()),
|
||||
)?;
|
||||
|
||||
if let Err(err) = rpc_client.get_account(&nonce_account) {
|
||||
return Err(CliError::BadParameter(format!(
|
||||
"Unable to advance nonce account {}. error: {}",
|
||||
nonce_account, err
|
||||
))
|
||||
let nonce_account_check =
|
||||
rpc_client.get_account_with_commitment(&nonce_account, config.commitment);
|
||||
if nonce_account_check.is_err() || nonce_account_check.unwrap().value.is_none() {
|
||||
return Err(CliError::BadParameter(
|
||||
"Unable to create new nonce, no nonce account found".to_string(),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
|
||||
let nonce_authority = config.signers[nonce_authority];
|
||||
let ix = advance_nonce_account(&nonce_account, &nonce_authority.pubkey());
|
||||
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
|
||||
let (recent_blockhash, fee_calculator, _) = rpc_client
|
||||
.get_recent_blockhash_with_commitment(config.commitment)?
|
||||
.value;
|
||||
let message = Message::new(&[ix], Some(&config.signers[0].pubkey()));
|
||||
let mut tx = Transaction::new_unsigned(message);
|
||||
tx.try_sign(&config.signers, recent_blockhash)?;
|
||||
@@ -478,7 +495,11 @@ pub fn process_new_nonce(
|
||||
&tx.message,
|
||||
config.commitment,
|
||||
)?;
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner_and_config(
|
||||
&tx,
|
||||
config.commitment,
|
||||
config.send_transaction_config,
|
||||
);
|
||||
log_instruction_custom_error::<SystemError>(result, &config)
|
||||
}
|
||||
|
||||
@@ -520,7 +541,9 @@ pub fn process_withdraw_from_nonce_account(
|
||||
destination_account_pubkey: &Pubkey,
|
||||
lamports: u64,
|
||||
) -> ProcessResult {
|
||||
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
|
||||
let (recent_blockhash, fee_calculator, _) = rpc_client
|
||||
.get_recent_blockhash_with_commitment(config.commitment)?
|
||||
.value;
|
||||
|
||||
let nonce_authority = config.signers[nonce_authority];
|
||||
let ix = withdraw_nonce_account(
|
||||
@@ -539,7 +562,11 @@ pub fn process_withdraw_from_nonce_account(
|
||||
&tx.message,
|
||||
config.commitment,
|
||||
)?;
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner_and_config(
|
||||
&tx,
|
||||
config.commitment,
|
||||
config.send_transaction_config,
|
||||
);
|
||||
log_instruction_custom_error::<NonceError>(result, &config)
|
||||
}
|
||||
|
||||
@@ -553,7 +580,6 @@ mod tests {
|
||||
fee_calculator::FeeCalculator,
|
||||
hash::hash,
|
||||
nonce::{self, state::Versions, State},
|
||||
nonce_account,
|
||||
signature::{read_keypair_file, write_keypair, Keypair, Signer},
|
||||
system_program,
|
||||
};
|
||||
@@ -865,7 +891,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_account_identity_ok() {
|
||||
let nonce_account = nonce_account::create_account(1).into_inner();
|
||||
let nonce_account = nonce::create_account(1).into_inner();
|
||||
assert_eq!(account_identity_ok(&nonce_account), Ok(()));
|
||||
|
||||
let system_account = Account::new(1, 0, &system_program::id());
|
||||
@@ -884,7 +910,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_state_from_account() {
|
||||
let mut nonce_account = nonce_account::create_account(1).into_inner();
|
||||
let mut nonce_account = nonce::create_account(1).into_inner();
|
||||
assert_eq!(state_from_account(&nonce_account), Ok(State::Uninitialized));
|
||||
|
||||
let data = nonce::state::Data {
|
||||
@@ -909,7 +935,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_data_from_helpers() {
|
||||
let mut nonce_account = nonce_account::create_account(1).into_inner();
|
||||
let mut nonce_account = nonce::create_account(1).into_inner();
|
||||
let state = state_from_account(&nonce_account).unwrap();
|
||||
assert_eq!(
|
||||
data_from_state(&state),
|
||||
|
2146
cli/src/program.rs
2146
cli/src/program.rs
File diff suppressed because it is too large
Load Diff
204
cli/src/stake.rs
204
cli/src/stake.rs
@@ -31,17 +31,17 @@ use solana_client::{
|
||||
rpc_request::{self, DELINQUENT_VALIDATOR_SLOT_DISTANCE},
|
||||
};
|
||||
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
|
||||
use solana_runtime::{feature::Feature, feature_set};
|
||||
use solana_sdk::{
|
||||
account::from_account,
|
||||
account_utils::StateMut,
|
||||
clock::{Clock, Epoch, Slot, UnixTimestamp, SECONDS_PER_DAY},
|
||||
feature, feature_set,
|
||||
message::Message,
|
||||
pubkey::Pubkey,
|
||||
system_instruction::SystemError,
|
||||
sysvar::{
|
||||
clock,
|
||||
stake_history::{self, StakeHistory},
|
||||
Sysvar,
|
||||
},
|
||||
transaction::Transaction,
|
||||
};
|
||||
@@ -64,12 +64,6 @@ pub const WITHDRAW_AUTHORITY_ARG: ArgConstant<'static> = ArgConstant {
|
||||
help: "Authorized withdrawer [default: cli config keypair]",
|
||||
};
|
||||
|
||||
pub const CUSTODIAN_ARG: ArgConstant<'static> = ArgConstant {
|
||||
name: "custodian",
|
||||
long: "custodian",
|
||||
help: "Authority to override account lockup",
|
||||
};
|
||||
|
||||
fn stake_authority_arg<'a, 'b>() -> Arg<'a, 'b> {
|
||||
Arg::with_name(STAKE_AUTHORITY_ARG.name)
|
||||
.long(STAKE_AUTHORITY_ARG.long)
|
||||
@@ -88,15 +82,6 @@ fn withdraw_authority_arg<'a, 'b>() -> Arg<'a, 'b> {
|
||||
.help(WITHDRAW_AUTHORITY_ARG.help)
|
||||
}
|
||||
|
||||
fn custodian_arg<'a, 'b>() -> Arg<'a, 'b> {
|
||||
Arg::with_name(CUSTODIAN_ARG.name)
|
||||
.long(CUSTODIAN_ARG.long)
|
||||
.takes_value(true)
|
||||
.value_name("KEYPAIR")
|
||||
.validator(is_valid_signer)
|
||||
.help(CUSTODIAN_ARG.help)
|
||||
}
|
||||
|
||||
pub trait StakeSubCommands {
|
||||
fn stake_subcommands(self) -> Self;
|
||||
}
|
||||
@@ -176,7 +161,7 @@ impl StakeSubCommands for App<'_, '_> {
|
||||
.validator(is_valid_signer)
|
||||
.help("Source account of funds [default: cli config keypair]"),
|
||||
)
|
||||
.offline_args()
|
||||
.offline_args(false)
|
||||
.nonce_args(false)
|
||||
.arg(fee_payer_arg())
|
||||
)
|
||||
@@ -205,7 +190,7 @@ impl StakeSubCommands for App<'_, '_> {
|
||||
"The vote account to which the stake will be delegated")
|
||||
)
|
||||
.arg(stake_authority_arg())
|
||||
.offline_args()
|
||||
.offline_args(false)
|
||||
.nonce_args(false)
|
||||
.arg(fee_payer_arg())
|
||||
)
|
||||
@@ -235,10 +220,9 @@ impl StakeSubCommands for App<'_, '_> {
|
||||
)
|
||||
.arg(stake_authority_arg())
|
||||
.arg(withdraw_authority_arg())
|
||||
.offline_args()
|
||||
.offline_args(false)
|
||||
.nonce_args(false)
|
||||
.arg(fee_payer_arg())
|
||||
.arg(custodian_arg())
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("deactivate-stake")
|
||||
@@ -251,7 +235,7 @@ impl StakeSubCommands for App<'_, '_> {
|
||||
"Stake account to be deactivated. ")
|
||||
)
|
||||
.arg(stake_authority_arg())
|
||||
.offline_args()
|
||||
.offline_args(false)
|
||||
.nonce_args(false)
|
||||
.arg(fee_payer_arg())
|
||||
)
|
||||
@@ -291,7 +275,7 @@ impl StakeSubCommands for App<'_, '_> {
|
||||
.help("Seed for address generation; if specified, the resulting account will be at a derived address of the SPLIT STAKE ACCOUNT pubkey")
|
||||
)
|
||||
.arg(stake_authority_arg())
|
||||
.offline_args()
|
||||
.offline_args(false)
|
||||
.nonce_args(false)
|
||||
.arg(fee_payer_arg())
|
||||
)
|
||||
@@ -313,7 +297,7 @@ impl StakeSubCommands for App<'_, '_> {
|
||||
"Source stake account for the merge. If successful, this stake account will no longer exist after the merge")
|
||||
)
|
||||
.arg(stake_authority_arg())
|
||||
.offline_args()
|
||||
.offline_args(false)
|
||||
.nonce_args(false)
|
||||
.arg(fee_payer_arg())
|
||||
)
|
||||
@@ -344,10 +328,17 @@ impl StakeSubCommands for App<'_, '_> {
|
||||
.help("The amount to withdraw from the stake account, in SOL")
|
||||
)
|
||||
.arg(withdraw_authority_arg())
|
||||
.offline_args()
|
||||
.offline_args(false)
|
||||
.nonce_args(false)
|
||||
.arg(fee_payer_arg())
|
||||
.arg(custodian_arg())
|
||||
.arg(
|
||||
Arg::with_name("custodian")
|
||||
.long("custodian")
|
||||
.takes_value(true)
|
||||
.value_name("KEYPAIR")
|
||||
.validator(is_valid_signer)
|
||||
.help("Authority to override account lockup")
|
||||
)
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("stake-set-lockup")
|
||||
@@ -392,7 +383,7 @@ impl StakeSubCommands for App<'_, '_> {
|
||||
.validator(is_valid_signer)
|
||||
.help("Keypair of the existing custodian [default: cli config pubkey]")
|
||||
)
|
||||
.offline_args()
|
||||
.offline_args(false)
|
||||
.nonce_args(false)
|
||||
.arg(fee_payer_arg())
|
||||
)
|
||||
@@ -412,7 +403,7 @@ impl StakeSubCommands for App<'_, '_> {
|
||||
.long("lamports")
|
||||
.takes_value(false)
|
||||
.help("Display balance in lamports instead of SOL")
|
||||
),
|
||||
)
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("stake-history")
|
||||
@@ -570,15 +561,11 @@ pub fn parse_stake_authorize(
|
||||
let (nonce_authority, nonce_authority_pubkey) =
|
||||
signer_of(matches, NONCE_AUTHORITY_ARG.name, wallet_manager)?;
|
||||
let (fee_payer, fee_payer_pubkey) = signer_of(matches, FEE_PAYER_ARG.name, wallet_manager)?;
|
||||
let (custodian, custodian_pubkey) = signer_of(matches, "custodian", wallet_manager)?;
|
||||
|
||||
bulk_signers.push(fee_payer);
|
||||
if nonce_account.is_some() {
|
||||
bulk_signers.push(nonce_authority);
|
||||
}
|
||||
if custodian.is_some() {
|
||||
bulk_signers.push(custodian);
|
||||
}
|
||||
let signer_info =
|
||||
default_signer.generate_unique_signers(bulk_signers, matches, wallet_manager)?;
|
||||
|
||||
@@ -604,7 +591,6 @@ pub fn parse_stake_authorize(
|
||||
nonce_account,
|
||||
nonce_authority: signer_info.index_of(nonce_authority_pubkey).unwrap(),
|
||||
fee_payer: signer_info.index_of(fee_payer_pubkey).unwrap(),
|
||||
custodian: custodian_pubkey.and_then(|_| signer_info.index_of(custodian_pubkey)),
|
||||
},
|
||||
signers: signer_info.signers,
|
||||
})
|
||||
@@ -973,7 +959,11 @@ pub fn process_create_stake_account(
|
||||
return_signers(&tx, &config.output_format)
|
||||
} else {
|
||||
tx.try_sign(&config.signers, recent_blockhash)?;
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner_and_config(
|
||||
&tx,
|
||||
config.commitment,
|
||||
config.send_transaction_config,
|
||||
);
|
||||
log_instruction_custom_error::<SystemError>(result, &config)
|
||||
}
|
||||
}
|
||||
@@ -984,7 +974,6 @@ pub fn process_stake_authorize(
|
||||
config: &CliConfig,
|
||||
stake_account_pubkey: &Pubkey,
|
||||
new_authorizations: &[(StakeAuthorize, Pubkey, SignerIndex)],
|
||||
custodian: Option<SignerIndex>,
|
||||
sign_only: bool,
|
||||
blockhash_query: &BlockhashQuery,
|
||||
nonce_account: Option<Pubkey>,
|
||||
@@ -992,7 +981,6 @@ pub fn process_stake_authorize(
|
||||
fee_payer: SignerIndex,
|
||||
) -> ProcessResult {
|
||||
let mut ixs = Vec::new();
|
||||
let custodian = custodian.map(|index| config.signers[index]);
|
||||
for (stake_authorize, authorized_pubkey, authority) in new_authorizations.iter() {
|
||||
check_unique_pubkeys(
|
||||
(stake_account_pubkey, "stake_account_pubkey".to_string()),
|
||||
@@ -1004,7 +992,6 @@ pub fn process_stake_authorize(
|
||||
&authority.pubkey(), // currently authorized
|
||||
authorized_pubkey, // new stake signer
|
||||
*stake_authorize, // stake or withdraw
|
||||
custodian.map(|signer| signer.pubkey()).as_ref(),
|
||||
));
|
||||
}
|
||||
|
||||
@@ -1046,7 +1033,11 @@ pub fn process_stake_authorize(
|
||||
&tx.message,
|
||||
config.commitment,
|
||||
)?;
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner_and_config(
|
||||
&tx,
|
||||
config.commitment,
|
||||
config.send_transaction_config,
|
||||
);
|
||||
log_instruction_custom_error::<StakeError>(result, &config)
|
||||
}
|
||||
}
|
||||
@@ -1105,7 +1096,11 @@ pub fn process_deactivate_stake_account(
|
||||
&tx.message,
|
||||
config.commitment,
|
||||
)?;
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner_and_config(
|
||||
&tx,
|
||||
config.commitment,
|
||||
config.send_transaction_config,
|
||||
);
|
||||
log_instruction_custom_error::<StakeError>(result, &config)
|
||||
}
|
||||
}
|
||||
@@ -1173,7 +1168,11 @@ pub fn process_withdraw_stake(
|
||||
&tx.message,
|
||||
config.commitment,
|
||||
)?;
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner_and_config(
|
||||
&tx,
|
||||
config.commitment,
|
||||
config.send_transaction_config,
|
||||
);
|
||||
log_instruction_custom_error::<SystemError>(result, &config)
|
||||
}
|
||||
}
|
||||
@@ -1312,7 +1311,11 @@ pub fn process_split_stake(
|
||||
&tx.message,
|
||||
config.commitment,
|
||||
)?;
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner_and_config(
|
||||
&tx,
|
||||
config.commitment,
|
||||
config.send_transaction_config,
|
||||
);
|
||||
log_instruction_custom_error::<StakeError>(result, &config)
|
||||
}
|
||||
}
|
||||
@@ -1476,7 +1479,11 @@ pub fn process_stake_set_lockup(
|
||||
&tx.message,
|
||||
config.commitment,
|
||||
)?;
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner_and_config(
|
||||
&tx,
|
||||
config.commitment,
|
||||
config.send_transaction_config,
|
||||
);
|
||||
log_instruction_custom_error::<StakeError>(result, &config)
|
||||
}
|
||||
}
|
||||
@@ -1521,7 +1528,6 @@ pub fn build_stake_state(
|
||||
CliStakeState {
|
||||
stake_type: CliStakeType::Stake,
|
||||
account_balance,
|
||||
credits_observed: Some(stake.credits_observed),
|
||||
delegated_stake: Some(stake.delegation.stake),
|
||||
delegated_vote_account_address: if stake.delegation.voter_pubkey
|
||||
!= Pubkey::default()
|
||||
@@ -1573,7 +1579,6 @@ pub fn build_stake_state(
|
||||
CliStakeState {
|
||||
stake_type: CliStakeType::Initialized,
|
||||
account_balance,
|
||||
credits_observed: Some(0),
|
||||
authorized: Some(authorized.into()),
|
||||
lockup,
|
||||
use_lamports_unit,
|
||||
@@ -1618,9 +1623,9 @@ pub(crate) fn fetch_epoch_rewards(
|
||||
kind:
|
||||
ClientErrorKind::RpcError(rpc_request::RpcError::RpcResponseError {
|
||||
code: rpc_custom_error::JSON_RPC_SERVER_ERROR_BLOCK_NOT_AVAILABLE,
|
||||
..
|
||||
message: _,
|
||||
}),
|
||||
..
|
||||
request: _,
|
||||
}) => {
|
||||
// RPC node doesn't have this block
|
||||
break;
|
||||
@@ -1640,37 +1645,29 @@ pub(crate) fn fetch_epoch_rewards(
|
||||
let previous_epoch_rewards = first_confirmed_block.rewards;
|
||||
|
||||
if let Some((effective_slot, epoch_end_time, epoch_rewards)) = epoch_info {
|
||||
let wallclock_epoch_duration = if epoch_end_time > epoch_start_time {
|
||||
Some(
|
||||
{ Local.timestamp(epoch_end_time, 0) - Local.timestamp(epoch_start_time, 0) }
|
||||
.to_std()?
|
||||
.as_secs_f64(),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let wallclock_epoch_duration =
|
||||
{ Local.timestamp(epoch_end_time, 0) - Local.timestamp(epoch_start_time, 0) }
|
||||
.to_std()?
|
||||
.as_secs_f64();
|
||||
|
||||
let wallclock_epochs_per_year =
|
||||
(SECONDS_PER_DAY * 356) as f64 / wallclock_epoch_duration;
|
||||
|
||||
if let Some(reward) = epoch_rewards
|
||||
.into_iter()
|
||||
.find(|reward| reward.pubkey == address.to_string())
|
||||
{
|
||||
if reward.post_balance > reward.lamports.try_into().unwrap_or(0) {
|
||||
let rate_change = reward.lamports.abs() as f64
|
||||
let balance_increase_percent = reward.lamports.abs() as f64
|
||||
/ (reward.post_balance as f64 - reward.lamports as f64);
|
||||
|
||||
let apr = wallclock_epoch_duration.map(|wallclock_epoch_duration| {
|
||||
let wallclock_epochs_per_year =
|
||||
(SECONDS_PER_DAY * 356) as f64 / wallclock_epoch_duration;
|
||||
rate_change * wallclock_epochs_per_year
|
||||
});
|
||||
|
||||
all_epoch_rewards.push(CliEpochReward {
|
||||
epoch,
|
||||
effective_slot,
|
||||
amount: reward.lamports.abs() as u64,
|
||||
post_balance: reward.post_balance,
|
||||
percent_change: rate_change * 100.0,
|
||||
apr: apr.map(|r| r * 100.0),
|
||||
percent_change: balance_increase_percent,
|
||||
apr: balance_increase_percent * wallclock_epochs_per_year,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1704,11 +1701,12 @@ pub fn process_show_stake_account(
|
||||
match stake_account.state() {
|
||||
Ok(stake_state) => {
|
||||
let stake_history_account = rpc_client.get_account(&stake_history::id())?;
|
||||
let stake_history = from_account(&stake_history_account).ok_or_else(|| {
|
||||
CliError::RpcRequestError("Failed to deserialize stake history".to_string())
|
||||
})?;
|
||||
let stake_history =
|
||||
StakeHistory::from_account(&stake_history_account).ok_or_else(|| {
|
||||
CliError::RpcRequestError("Failed to deserialize stake history".to_string())
|
||||
})?;
|
||||
let clock_account = rpc_client.get_account(&clock::id())?;
|
||||
let clock: Clock = from_account(&clock_account).ok_or_else(|| {
|
||||
let clock: Clock = Sysvar::from_account(&clock_account).ok_or_else(|| {
|
||||
CliError::RpcRequestError("Failed to deserialize clock sysvar".to_string())
|
||||
})?;
|
||||
|
||||
@@ -1718,17 +1716,16 @@ pub fn process_show_stake_account(
|
||||
use_lamports_unit,
|
||||
&stake_history,
|
||||
&clock,
|
||||
is_stake_program_v2_enabled(rpc_client)?, // At v1.6, this check can be removed and simply passed as `true`
|
||||
is_stake_program_v2_enabled(rpc_client), // At v1.6, this check can be removed and simply passed as `true`
|
||||
);
|
||||
|
||||
if state.stake_type == CliStakeType::Stake {
|
||||
if let Some(activation_epoch) = state.activation_epoch {
|
||||
let rewards =
|
||||
fetch_epoch_rewards(rpc_client, stake_account_address, activation_epoch);
|
||||
match rewards {
|
||||
Ok(rewards) => state.epoch_rewards = Some(rewards),
|
||||
Err(error) => eprintln!("Failed to fetch epoch rewards: {:?}", error),
|
||||
};
|
||||
state.epoch_rewards = Some(fetch_epoch_rewards(
|
||||
rpc_client,
|
||||
stake_account_address,
|
||||
activation_epoch,
|
||||
)?);
|
||||
}
|
||||
}
|
||||
Ok(config.output_format.formatted_string(&state))
|
||||
@@ -1747,7 +1744,7 @@ pub fn process_show_stake_history(
|
||||
use_lamports_unit: bool,
|
||||
) -> ProcessResult {
|
||||
let stake_history_account = rpc_client.get_account(&stake_history::id())?;
|
||||
let stake_history = from_account::<StakeHistory>(&stake_history_account).ok_or_else(|| {
|
||||
let stake_history = StakeHistory::from_account(&stake_history_account).ok_or_else(|| {
|
||||
CliError::RpcRequestError("Failed to deserialize stake history".to_string())
|
||||
})?;
|
||||
|
||||
@@ -1785,15 +1782,23 @@ pub fn process_delegate_stake(
|
||||
if !sign_only {
|
||||
// Sanity check the vote account to ensure it is attached to a validator that has recently
|
||||
// voted at the tip of the ledger
|
||||
let vote_account_data = rpc_client
|
||||
.get_account(vote_account_pubkey)
|
||||
.map_err(|err| {
|
||||
let vote_account = rpc_client
|
||||
.get_account_with_commitment(vote_account_pubkey, config.commitment)
|
||||
.map_err(|_| {
|
||||
CliError::RpcRequestError(format!(
|
||||
"Vote account not found: {}. error: {}",
|
||||
vote_account_pubkey, err,
|
||||
"Vote account not found: {}",
|
||||
vote_account_pubkey
|
||||
))
|
||||
})?
|
||||
.data;
|
||||
})?;
|
||||
let vote_account_data = if let Some(account) = vote_account.value {
|
||||
account.data
|
||||
} else {
|
||||
return Err(CliError::RpcRequestError(format!(
|
||||
"Vote account not found: {}",
|
||||
vote_account_pubkey
|
||||
))
|
||||
.into());
|
||||
};
|
||||
|
||||
let vote_state = VoteState::deserialize(&vote_account_data).map_err(|_| {
|
||||
CliError::RpcRequestError(
|
||||
@@ -1873,18 +1878,22 @@ pub fn process_delegate_stake(
|
||||
&tx.message,
|
||||
config.commitment,
|
||||
)?;
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner_and_config(
|
||||
&tx,
|
||||
config.commitment,
|
||||
config.send_transaction_config,
|
||||
);
|
||||
log_instruction_custom_error::<StakeError>(result, &config)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_stake_program_v2_enabled(
|
||||
rpc_client: &RpcClient,
|
||||
) -> Result<bool, Box<dyn std::error::Error>> {
|
||||
let feature_account = rpc_client.get_account(&feature_set::stake_program_v2::id())?;
|
||||
Ok(feature::from_account(&feature_account)
|
||||
pub fn is_stake_program_v2_enabled(rpc_client: &RpcClient) -> bool {
|
||||
rpc_client
|
||||
.get_account(&feature_set::stake_program_v2::id())
|
||||
.ok()
|
||||
.and_then(|account| Feature::from_account(&account))
|
||||
.and_then(|feature| feature.activated_at)
|
||||
.is_some())
|
||||
.is_some()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -1956,7 +1965,6 @@ mod tests {
|
||||
nonce_account: None,
|
||||
nonce_authority: 0,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
},
|
||||
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into(),],
|
||||
},
|
||||
@@ -1991,7 +1999,6 @@ mod tests {
|
||||
nonce_account: None,
|
||||
nonce_authority: 0,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
},
|
||||
signers: vec![
|
||||
read_keypair_file(&default_keypair_file).unwrap().into(),
|
||||
@@ -2030,7 +2037,6 @@ mod tests {
|
||||
nonce_account: None,
|
||||
nonce_authority: 0,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
},
|
||||
signers: vec![
|
||||
read_keypair_file(&default_keypair_file).unwrap().into(),
|
||||
@@ -2058,7 +2064,6 @@ mod tests {
|
||||
nonce_account: None,
|
||||
nonce_authority: 0,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
},
|
||||
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into(),],
|
||||
},
|
||||
@@ -2083,7 +2088,6 @@ mod tests {
|
||||
nonce_account: None,
|
||||
nonce_authority: 0,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
},
|
||||
signers: vec![
|
||||
read_keypair_file(&default_keypair_file).unwrap().into(),
|
||||
@@ -2114,7 +2118,6 @@ mod tests {
|
||||
nonce_account: None,
|
||||
nonce_authority: 0,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
},
|
||||
signers: vec![
|
||||
read_keypair_file(&default_keypair_file).unwrap().into(),
|
||||
@@ -2146,7 +2149,6 @@ mod tests {
|
||||
nonce_account: None,
|
||||
nonce_authority: 0,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
},
|
||||
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into(),],
|
||||
},
|
||||
@@ -2175,7 +2177,6 @@ mod tests {
|
||||
nonce_account: None,
|
||||
nonce_authority: 0,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
},
|
||||
signers: vec![
|
||||
read_keypair_file(&default_keypair_file).unwrap().into(),
|
||||
@@ -2210,7 +2211,6 @@ mod tests {
|
||||
nonce_account: None,
|
||||
nonce_authority: 0,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
},
|
||||
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
|
||||
}
|
||||
@@ -2247,7 +2247,6 @@ mod tests {
|
||||
nonce_account: None,
|
||||
nonce_authority: 0,
|
||||
fee_payer: 1,
|
||||
custodian: None,
|
||||
},
|
||||
signers: vec![
|
||||
read_keypair_file(&default_keypair_file).unwrap().into(),
|
||||
@@ -2294,7 +2293,6 @@ mod tests {
|
||||
nonce_account: Some(nonce_account),
|
||||
nonce_authority: 2,
|
||||
fee_payer: 1,
|
||||
custodian: None,
|
||||
},
|
||||
signers: vec![
|
||||
read_keypair_file(&default_keypair_file).unwrap().into(),
|
||||
@@ -2327,7 +2325,6 @@ mod tests {
|
||||
nonce_account: None,
|
||||
nonce_authority: 0,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
},
|
||||
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
|
||||
}
|
||||
@@ -2365,7 +2362,6 @@ mod tests {
|
||||
nonce_account: Some(nonce_account_pubkey),
|
||||
nonce_authority: 1,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
},
|
||||
signers: vec![
|
||||
read_keypair_file(&default_keypair_file).unwrap().into(),
|
||||
@@ -2399,7 +2395,6 @@ mod tests {
|
||||
nonce_account: None,
|
||||
nonce_authority: 0,
|
||||
fee_payer: 1,
|
||||
custodian: None,
|
||||
},
|
||||
signers: vec![
|
||||
read_keypair_file(&default_keypair_file).unwrap().into(),
|
||||
@@ -2437,7 +2432,6 @@ mod tests {
|
||||
nonce_account: None,
|
||||
nonce_authority: 0,
|
||||
fee_payer: 1,
|
||||
custodian: None,
|
||||
},
|
||||
signers: vec![
|
||||
read_keypair_file(&default_keypair_file).unwrap().into(),
|
||||
|
@@ -20,6 +20,7 @@ use solana_config_program::{config_instruction, get_config_data, ConfigKeys, Con
|
||||
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
|
||||
use solana_sdk::{
|
||||
account::Account,
|
||||
commitment_config::CommitmentConfig,
|
||||
message::Message,
|
||||
pubkey::Pubkey,
|
||||
signature::{Keypair, Signer},
|
||||
@@ -287,7 +288,9 @@ pub fn process_set_validator_info(
|
||||
};
|
||||
|
||||
// Check existence of validator-info account
|
||||
let balance = rpc_client.get_balance(&info_pubkey).unwrap_or(0);
|
||||
let balance = rpc_client
|
||||
.poll_get_balance_with_commitment(&info_pubkey, CommitmentConfig::default())
|
||||
.unwrap_or(0);
|
||||
|
||||
let lamports =
|
||||
rpc_client.get_minimum_balance_for_rent_exemption(ValidatorInfo::max_space() as usize)?;
|
||||
|
@@ -8,6 +8,7 @@ use crate::{
|
||||
};
|
||||
use clap::{value_t_or_exit, App, Arg, ArgMatches, SubCommand};
|
||||
use solana_clap_utils::{
|
||||
commitment::commitment_arg,
|
||||
input_parsers::*,
|
||||
input_validators::*,
|
||||
keypair::{DefaultSigner, SignerIndex},
|
||||
@@ -207,7 +208,8 @@ impl VoteSubCommands for App<'_, '_> {
|
||||
.long("lamports")
|
||||
.takes_value(false)
|
||||
.help("Display balance in lamports instead of SOL"),
|
||||
),
|
||||
)
|
||||
.arg(commitment_arg()),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("withdraw-from-vote-account")
|
||||
@@ -492,7 +494,9 @@ pub fn process_create_vote_account(
|
||||
}
|
||||
}
|
||||
|
||||
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
|
||||
let (recent_blockhash, fee_calculator, _) = rpc_client
|
||||
.get_recent_blockhash_with_commitment(config.commitment)?
|
||||
.value;
|
||||
|
||||
let (message, _) = resolve_spend_tx_and_check_account_balance(
|
||||
rpc_client,
|
||||
@@ -505,7 +509,11 @@ pub fn process_create_vote_account(
|
||||
)?;
|
||||
let mut tx = Transaction::new_unsigned(message);
|
||||
tx.try_sign(&config.signers, recent_blockhash)?;
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner_and_config(
|
||||
&tx,
|
||||
config.commitment,
|
||||
config.send_transaction_config,
|
||||
);
|
||||
log_instruction_custom_error::<SystemError>(result, &config)
|
||||
}
|
||||
|
||||
@@ -528,7 +536,9 @@ pub fn process_vote_authorize(
|
||||
(&authorized.pubkey(), "authorized_account".to_string()),
|
||||
(new_authorized_pubkey, "new_authorized_pubkey".to_string()),
|
||||
)?;
|
||||
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
|
||||
let (recent_blockhash, fee_calculator, _) = rpc_client
|
||||
.get_recent_blockhash_with_commitment(config.commitment)?
|
||||
.value;
|
||||
let ixs = vec![vote_instruction::authorize(
|
||||
vote_account_pubkey, // vote account to update
|
||||
&authorized.pubkey(), // current authorized
|
||||
@@ -546,7 +556,11 @@ pub fn process_vote_authorize(
|
||||
&tx.message,
|
||||
config.commitment,
|
||||
)?;
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner_and_config(
|
||||
&tx,
|
||||
config.commitment,
|
||||
config.send_transaction_config,
|
||||
);
|
||||
log_instruction_custom_error::<VoteError>(result, &config)
|
||||
}
|
||||
|
||||
@@ -564,7 +578,9 @@ pub fn process_vote_update_validator(
|
||||
(vote_account_pubkey, "vote_account_pubkey".to_string()),
|
||||
(&new_identity_pubkey, "new_identity_account".to_string()),
|
||||
)?;
|
||||
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
|
||||
let (recent_blockhash, fee_calculator, _) = rpc_client
|
||||
.get_recent_blockhash_with_commitment(config.commitment)?
|
||||
.value;
|
||||
let ixs = vec![vote_instruction::update_validator_identity(
|
||||
vote_account_pubkey,
|
||||
&authorized_withdrawer.pubkey(),
|
||||
@@ -581,7 +597,11 @@ pub fn process_vote_update_validator(
|
||||
&tx.message,
|
||||
config.commitment,
|
||||
)?;
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner_and_config(
|
||||
&tx,
|
||||
config.commitment,
|
||||
config.send_transaction_config,
|
||||
);
|
||||
log_instruction_custom_error::<VoteError>(result, &config)
|
||||
}
|
||||
|
||||
@@ -593,7 +613,9 @@ pub fn process_vote_update_commission(
|
||||
withdraw_authority: SignerIndex,
|
||||
) -> ProcessResult {
|
||||
let authorized_withdrawer = config.signers[withdraw_authority];
|
||||
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
|
||||
let (recent_blockhash, fee_calculator, _) = rpc_client
|
||||
.get_recent_blockhash_with_commitment(config.commitment)?
|
||||
.value;
|
||||
let ixs = vec![vote_instruction::update_commission(
|
||||
vote_account_pubkey,
|
||||
&authorized_withdrawer.pubkey(),
|
||||
@@ -610,7 +632,11 @@ pub fn process_vote_update_commission(
|
||||
&tx.message,
|
||||
config.commitment,
|
||||
)?;
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner_and_config(
|
||||
&tx,
|
||||
config.commitment,
|
||||
config.send_transaction_config,
|
||||
);
|
||||
log_instruction_custom_error::<VoteError>(result, &config)
|
||||
}
|
||||
|
||||
@@ -670,14 +696,11 @@ pub fn process_show_vote_account(
|
||||
}
|
||||
}
|
||||
|
||||
let epoch_rewards = match crate::stake::fetch_epoch_rewards(rpc_client, vote_account_address, 1)
|
||||
{
|
||||
Ok(rewards) => Some(rewards),
|
||||
Err(error) => {
|
||||
eprintln!("Failed to fetch epoch rewards: {:?}", error);
|
||||
None
|
||||
}
|
||||
};
|
||||
let epoch_rewards = Some(crate::stake::fetch_epoch_rewards(
|
||||
rpc_client,
|
||||
vote_account_address,
|
||||
1,
|
||||
)?);
|
||||
|
||||
let vote_account_data = CliVoteAccount {
|
||||
account_balance: vote_account.lamports,
|
||||
@@ -705,10 +728,14 @@ pub fn process_withdraw_from_vote_account(
|
||||
withdraw_amount: SpendAmount,
|
||||
destination_account_pubkey: &Pubkey,
|
||||
) -> ProcessResult {
|
||||
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
|
||||
let (recent_blockhash, fee_calculator, _) = rpc_client
|
||||
.get_recent_blockhash_with_commitment(config.commitment)?
|
||||
.value;
|
||||
let withdraw_authority = config.signers[withdraw_authority];
|
||||
|
||||
let current_balance = rpc_client.get_balance(&vote_account_pubkey)?;
|
||||
let current_balance = rpc_client
|
||||
.get_balance_with_commitment(&vote_account_pubkey, config.commitment)?
|
||||
.value;
|
||||
let minimum_balance = rpc_client.get_minimum_balance_for_rent_exemption(VoteState::size_of())?;
|
||||
|
||||
let lamports = match withdraw_amount {
|
||||
@@ -741,7 +768,11 @@ pub fn process_withdraw_from_vote_account(
|
||||
&transaction.message,
|
||||
config.commitment,
|
||||
)?;
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&transaction);
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner_and_config(
|
||||
&transaction,
|
||||
config.commitment,
|
||||
config.send_transaction_config,
|
||||
);
|
||||
log_instruction_custom_error::<VoteError>(result, &config)
|
||||
}
|
||||
|
||||
|
158
cli/tests/deploy.rs
Normal file
158
cli/tests/deploy.rs
Normal file
@@ -0,0 +1,158 @@
|
||||
use serde_json::Value;
|
||||
use solana_cli::cli::{process_command, CliCommand, CliConfig};
|
||||
use solana_client::rpc_client::RpcClient;
|
||||
use solana_core::test_validator::TestValidator;
|
||||
use solana_faucet::faucet::run_local_faucet;
|
||||
use solana_sdk::{
|
||||
bpf_loader,
|
||||
commitment_config::CommitmentConfig,
|
||||
pubkey::Pubkey,
|
||||
signature::{Keypair, Signer},
|
||||
};
|
||||
use std::{
|
||||
fs::{remove_dir_all, File},
|
||||
io::Read,
|
||||
path::PathBuf,
|
||||
str::FromStr,
|
||||
sync::mpsc::channel,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_cli_deploy_program() {
|
||||
solana_logger::setup();
|
||||
|
||||
let mut pathbuf = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
pathbuf.push("tests");
|
||||
pathbuf.push("fixtures");
|
||||
pathbuf.push("noop");
|
||||
pathbuf.set_extension("so");
|
||||
|
||||
let TestValidator {
|
||||
server,
|
||||
leader_data,
|
||||
alice,
|
||||
ledger_path,
|
||||
..
|
||||
} = TestValidator::run();
|
||||
|
||||
let (sender, receiver) = channel();
|
||||
run_local_faucet(alice, sender, None);
|
||||
let faucet_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client = RpcClient::new_socket(leader_data.rpc);
|
||||
|
||||
let mut file = File::open(pathbuf.to_str().unwrap()).unwrap();
|
||||
let mut program_data = Vec::new();
|
||||
file.read_to_end(&mut program_data).unwrap();
|
||||
let minimum_balance_for_rent_exemption = rpc_client
|
||||
.get_minimum_balance_for_rent_exemption(program_data.len())
|
||||
.unwrap();
|
||||
|
||||
let mut config = CliConfig::recent_for_tests();
|
||||
let keypair = Keypair::new();
|
||||
config.json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
config.command = CliCommand::Airdrop {
|
||||
faucet_host: None,
|
||||
faucet_port: faucet_addr.port(),
|
||||
pubkey: None,
|
||||
lamports: 4 * minimum_balance_for_rent_exemption, // min balance for rent exemption for three programs + leftover for tx processing
|
||||
};
|
||||
config.signers = vec![&keypair];
|
||||
process_command(&config).unwrap();
|
||||
|
||||
config.command = CliCommand::Deploy {
|
||||
program_location: pathbuf.to_str().unwrap().to_string(),
|
||||
address: None,
|
||||
use_deprecated_loader: false,
|
||||
allow_excessive_balance: false,
|
||||
};
|
||||
|
||||
let response = process_command(&config);
|
||||
let json: Value = serde_json::from_str(&response.unwrap()).unwrap();
|
||||
let program_id_str = json
|
||||
.as_object()
|
||||
.unwrap()
|
||||
.get("programId")
|
||||
.unwrap()
|
||||
.as_str()
|
||||
.unwrap();
|
||||
let program_id = Pubkey::from_str(&program_id_str).unwrap();
|
||||
let account0 = rpc_client
|
||||
.get_account_with_commitment(&program_id, CommitmentConfig::recent())
|
||||
.unwrap()
|
||||
.value
|
||||
.unwrap();
|
||||
assert_eq!(account0.lamports, minimum_balance_for_rent_exemption);
|
||||
assert_eq!(account0.owner, bpf_loader::id());
|
||||
assert_eq!(account0.executable, true);
|
||||
|
||||
let mut file = File::open(pathbuf.to_str().unwrap().to_string()).unwrap();
|
||||
let mut elf = Vec::new();
|
||||
file.read_to_end(&mut elf).unwrap();
|
||||
|
||||
assert_eq!(account0.data, elf);
|
||||
|
||||
// Test custom address
|
||||
let custom_address_keypair = Keypair::new();
|
||||
config.signers = vec![&keypair, &custom_address_keypair];
|
||||
config.command = CliCommand::Deploy {
|
||||
program_location: pathbuf.to_str().unwrap().to_string(),
|
||||
address: Some(1),
|
||||
use_deprecated_loader: false,
|
||||
allow_excessive_balance: false,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
let account1 = rpc_client
|
||||
.get_account_with_commitment(&custom_address_keypair.pubkey(), CommitmentConfig::recent())
|
||||
.unwrap()
|
||||
.value
|
||||
.unwrap();
|
||||
assert_eq!(account1.lamports, minimum_balance_for_rent_exemption);
|
||||
assert_eq!(account1.owner, bpf_loader::id());
|
||||
assert_eq!(account1.executable, true);
|
||||
assert_eq!(account0.data, account1.data);
|
||||
|
||||
// Attempt to redeploy to the same address
|
||||
process_command(&config).unwrap_err();
|
||||
|
||||
// Attempt to deploy to account with excess balance
|
||||
let custom_address_keypair = Keypair::new();
|
||||
config.command = CliCommand::Airdrop {
|
||||
faucet_host: None,
|
||||
faucet_port: faucet_addr.port(),
|
||||
pubkey: None,
|
||||
lamports: 2 * minimum_balance_for_rent_exemption, // Anything over minimum_balance_for_rent_exemption should trigger err
|
||||
};
|
||||
config.signers = vec![&custom_address_keypair];
|
||||
process_command(&config).unwrap();
|
||||
|
||||
config.signers = vec![&keypair, &custom_address_keypair];
|
||||
config.command = CliCommand::Deploy {
|
||||
program_location: pathbuf.to_str().unwrap().to_string(),
|
||||
address: Some(1),
|
||||
use_deprecated_loader: false,
|
||||
allow_excessive_balance: false,
|
||||
};
|
||||
process_command(&config).unwrap_err();
|
||||
|
||||
// Use forcing parameter to deploy to account with excess balance
|
||||
config.command = CliCommand::Deploy {
|
||||
program_location: pathbuf.to_str().unwrap().to_string(),
|
||||
address: Some(1),
|
||||
use_deprecated_loader: false,
|
||||
allow_excessive_balance: true,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
let account2 = rpc_client
|
||||
.get_account_with_commitment(&custom_address_keypair.pubkey(), CommitmentConfig::recent())
|
||||
.unwrap()
|
||||
.value
|
||||
.unwrap();
|
||||
assert_eq!(account2.lamports, 2 * minimum_balance_for_rent_exemption);
|
||||
assert_eq!(account2.owner, bpf_loader::id());
|
||||
assert_eq!(account2.executable, true);
|
||||
assert_eq!(account0.data, account2.data);
|
||||
|
||||
server.close().unwrap();
|
||||
remove_dir_all(ledger_path).unwrap();
|
||||
}
|
@@ -80,8 +80,7 @@ fn full_battery_tests(
|
||||
run_local_faucet(alice, sender, None);
|
||||
let faucet_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_socket_with_commitment(leader_data.rpc, CommitmentConfig::recent());
|
||||
let rpc_client = RpcClient::new_socket(leader_data.rpc);
|
||||
let json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
|
||||
let mut config_payer = CliConfig::recent_for_tests();
|
||||
@@ -251,8 +250,7 @@ fn test_create_account_with_seed() {
|
||||
let config = CliConfig::recent_for_tests();
|
||||
|
||||
// Setup accounts
|
||||
let rpc_client =
|
||||
RpcClient::new_socket_with_commitment(leader_data.rpc, CommitmentConfig::recent());
|
||||
let rpc_client = RpcClient::new_socket(leader_data.rpc);
|
||||
request_and_confirm_airdrop(
|
||||
&rpc_client,
|
||||
&faucet_addr,
|
||||
|
452
cli/tests/pay.rs
Normal file
452
cli/tests/pay.rs
Normal file
@@ -0,0 +1,452 @@
|
||||
use chrono::prelude::*;
|
||||
use serde_json::Value;
|
||||
use solana_cli::{
|
||||
cli::{process_command, request_and_confirm_airdrop, CliCommand, CliConfig, PayCommand},
|
||||
spend_utils::SpendAmount,
|
||||
test_utils::check_recent_balance,
|
||||
};
|
||||
use solana_cli_output::{parse_sign_only_reply_string, OutputFormat};
|
||||
use solana_client::{
|
||||
blockhash_query::{self, BlockhashQuery},
|
||||
nonce_utils,
|
||||
rpc_client::RpcClient,
|
||||
};
|
||||
use solana_core::test_validator::TestValidator;
|
||||
use solana_faucet::faucet::run_local_faucet;
|
||||
use solana_sdk::{
|
||||
commitment_config::CommitmentConfig,
|
||||
nonce::State as NonceState,
|
||||
pubkey::Pubkey,
|
||||
signature::{Keypair, Signer},
|
||||
};
|
||||
use std::{fs::remove_dir_all, sync::mpsc::channel};
|
||||
|
||||
#[test]
|
||||
fn test_cli_timestamp_tx() {
|
||||
let TestValidator {
|
||||
server,
|
||||
leader_data,
|
||||
alice,
|
||||
ledger_path,
|
||||
..
|
||||
} = TestValidator::run();
|
||||
let bob_pubkey = solana_sdk::pubkey::new_rand();
|
||||
|
||||
let (sender, receiver) = channel();
|
||||
run_local_faucet(alice, sender, None);
|
||||
let faucet_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client = RpcClient::new_socket(leader_data.rpc);
|
||||
let default_signer0 = Keypair::new();
|
||||
let default_signer1 = Keypair::new();
|
||||
|
||||
let mut config_payer = CliConfig::recent_for_tests();
|
||||
config_payer.json_rpc_url =
|
||||
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
config_payer.signers = vec![&default_signer0];
|
||||
|
||||
let mut config_witness = CliConfig::recent_for_tests();
|
||||
config_witness.json_rpc_url = config_payer.json_rpc_url.clone();
|
||||
config_witness.signers = vec![&default_signer1];
|
||||
|
||||
assert_ne!(
|
||||
config_payer.signers[0].pubkey(),
|
||||
config_witness.signers[0].pubkey()
|
||||
);
|
||||
|
||||
request_and_confirm_airdrop(
|
||||
&rpc_client,
|
||||
&faucet_addr,
|
||||
&config_payer.signers[0].pubkey(),
|
||||
50,
|
||||
&config_witness,
|
||||
)
|
||||
.unwrap();
|
||||
check_recent_balance(50, &rpc_client, &config_payer.signers[0].pubkey());
|
||||
|
||||
request_and_confirm_airdrop(
|
||||
&rpc_client,
|
||||
&faucet_addr,
|
||||
&config_witness.signers[0].pubkey(),
|
||||
1,
|
||||
&config_witness,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Make transaction (from config_payer to bob_pubkey) requiring timestamp from config_witness
|
||||
let date_string = "\"2018-09-19T17:30:59Z\"";
|
||||
let dt: DateTime<Utc> = serde_json::from_str(&date_string).unwrap();
|
||||
config_payer.command = CliCommand::Pay(PayCommand {
|
||||
amount: SpendAmount::Some(10),
|
||||
to: bob_pubkey,
|
||||
timestamp: Some(dt),
|
||||
timestamp_pubkey: Some(config_witness.signers[0].pubkey()),
|
||||
..PayCommand::default()
|
||||
});
|
||||
let sig_response = process_command(&config_payer);
|
||||
|
||||
let object: Value = serde_json::from_str(&sig_response.unwrap()).unwrap();
|
||||
let process_id_str = object.get("processId").unwrap().as_str().unwrap();
|
||||
let process_id_vec = bs58::decode(process_id_str)
|
||||
.into_vec()
|
||||
.expect("base58-encoded public key");
|
||||
let process_id = Pubkey::new(&process_id_vec);
|
||||
|
||||
check_recent_balance(40, &rpc_client, &config_payer.signers[0].pubkey()); // config_payer balance
|
||||
check_recent_balance(10, &rpc_client, &process_id); // contract balance
|
||||
check_recent_balance(0, &rpc_client, &bob_pubkey); // recipient balance
|
||||
|
||||
// Sign transaction by config_witness
|
||||
config_witness.command = CliCommand::TimeElapsed(bob_pubkey, process_id, dt);
|
||||
process_command(&config_witness).unwrap();
|
||||
|
||||
check_recent_balance(40, &rpc_client, &config_payer.signers[0].pubkey()); // config_payer balance
|
||||
check_recent_balance(0, &rpc_client, &process_id); // contract balance
|
||||
check_recent_balance(10, &rpc_client, &bob_pubkey); // recipient balance
|
||||
|
||||
server.close().unwrap();
|
||||
remove_dir_all(ledger_path).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cli_witness_tx() {
|
||||
let TestValidator {
|
||||
server,
|
||||
leader_data,
|
||||
alice,
|
||||
ledger_path,
|
||||
..
|
||||
} = TestValidator::run();
|
||||
let bob_pubkey = solana_sdk::pubkey::new_rand();
|
||||
|
||||
let (sender, receiver) = channel();
|
||||
run_local_faucet(alice, sender, None);
|
||||
let faucet_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client = RpcClient::new_socket(leader_data.rpc);
|
||||
let default_signer0 = Keypair::new();
|
||||
let default_signer1 = Keypair::new();
|
||||
|
||||
let mut config_payer = CliConfig::recent_for_tests();
|
||||
config_payer.json_rpc_url =
|
||||
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
config_payer.signers = vec![&default_signer0];
|
||||
|
||||
let mut config_witness = CliConfig::recent_for_tests();
|
||||
config_witness.json_rpc_url = config_payer.json_rpc_url.clone();
|
||||
config_witness.signers = vec![&default_signer1];
|
||||
|
||||
assert_ne!(
|
||||
config_payer.signers[0].pubkey(),
|
||||
config_witness.signers[0].pubkey()
|
||||
);
|
||||
|
||||
request_and_confirm_airdrop(
|
||||
&rpc_client,
|
||||
&faucet_addr,
|
||||
&config_payer.signers[0].pubkey(),
|
||||
50,
|
||||
&config_witness,
|
||||
)
|
||||
.unwrap();
|
||||
request_and_confirm_airdrop(
|
||||
&rpc_client,
|
||||
&faucet_addr,
|
||||
&config_witness.signers[0].pubkey(),
|
||||
1,
|
||||
&config_witness,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Make transaction (from config_payer to bob_pubkey) requiring witness signature from config_witness
|
||||
config_payer.command = CliCommand::Pay(PayCommand {
|
||||
amount: SpendAmount::Some(10),
|
||||
to: bob_pubkey,
|
||||
witnesses: Some(vec![config_witness.signers[0].pubkey()]),
|
||||
..PayCommand::default()
|
||||
});
|
||||
let sig_response = process_command(&config_payer);
|
||||
|
||||
let object: Value = serde_json::from_str(&sig_response.unwrap()).unwrap();
|
||||
let process_id_str = object.get("processId").unwrap().as_str().unwrap();
|
||||
let process_id_vec = bs58::decode(process_id_str)
|
||||
.into_vec()
|
||||
.expect("base58-encoded public key");
|
||||
let process_id = Pubkey::new(&process_id_vec);
|
||||
|
||||
check_recent_balance(40, &rpc_client, &config_payer.signers[0].pubkey()); // config_payer balance
|
||||
check_recent_balance(10, &rpc_client, &process_id); // contract balance
|
||||
check_recent_balance(0, &rpc_client, &bob_pubkey); // recipient balance
|
||||
|
||||
// Sign transaction by config_witness
|
||||
config_witness.command = CliCommand::Witness(bob_pubkey, process_id);
|
||||
process_command(&config_witness).unwrap();
|
||||
|
||||
check_recent_balance(40, &rpc_client, &config_payer.signers[0].pubkey()); // config_payer balance
|
||||
check_recent_balance(0, &rpc_client, &process_id); // contract balance
|
||||
check_recent_balance(10, &rpc_client, &bob_pubkey); // recipient balance
|
||||
|
||||
server.close().unwrap();
|
||||
remove_dir_all(ledger_path).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cli_cancel_tx() {
|
||||
let TestValidator {
|
||||
server,
|
||||
leader_data,
|
||||
alice,
|
||||
ledger_path,
|
||||
..
|
||||
} = TestValidator::run();
|
||||
let bob_pubkey = solana_sdk::pubkey::new_rand();
|
||||
|
||||
let (sender, receiver) = channel();
|
||||
run_local_faucet(alice, sender, None);
|
||||
let faucet_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client = RpcClient::new_socket(leader_data.rpc);
|
||||
let default_signer0 = Keypair::new();
|
||||
let default_signer1 = Keypair::new();
|
||||
|
||||
let mut config_payer = CliConfig::recent_for_tests();
|
||||
config_payer.json_rpc_url =
|
||||
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
config_payer.signers = vec![&default_signer0];
|
||||
|
||||
let mut config_witness = CliConfig::recent_for_tests();
|
||||
config_witness.json_rpc_url = config_payer.json_rpc_url.clone();
|
||||
config_witness.signers = vec![&default_signer1];
|
||||
|
||||
assert_ne!(
|
||||
config_payer.signers[0].pubkey(),
|
||||
config_witness.signers[0].pubkey()
|
||||
);
|
||||
|
||||
request_and_confirm_airdrop(
|
||||
&rpc_client,
|
||||
&faucet_addr,
|
||||
&config_payer.signers[0].pubkey(),
|
||||
50,
|
||||
&config_witness,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Make transaction (from config_payer to bob_pubkey) requiring witness signature from config_witness
|
||||
config_payer.command = CliCommand::Pay(PayCommand {
|
||||
amount: SpendAmount::Some(10),
|
||||
to: bob_pubkey,
|
||||
witnesses: Some(vec![config_witness.signers[0].pubkey()]),
|
||||
cancelable: true,
|
||||
..PayCommand::default()
|
||||
});
|
||||
let sig_response = process_command(&config_payer).unwrap();
|
||||
|
||||
let object: Value = serde_json::from_str(&sig_response).unwrap();
|
||||
let process_id_str = object.get("processId").unwrap().as_str().unwrap();
|
||||
let process_id_vec = bs58::decode(process_id_str)
|
||||
.into_vec()
|
||||
.expect("base58-encoded public key");
|
||||
let process_id = Pubkey::new(&process_id_vec);
|
||||
|
||||
check_recent_balance(40, &rpc_client, &config_payer.signers[0].pubkey()); // config_payer balance
|
||||
check_recent_balance(10, &rpc_client, &process_id); // contract balance
|
||||
check_recent_balance(0, &rpc_client, &bob_pubkey); // recipient balance
|
||||
|
||||
// Sign transaction by config_witness
|
||||
config_payer.command = CliCommand::Cancel(process_id);
|
||||
process_command(&config_payer).unwrap();
|
||||
|
||||
check_recent_balance(50, &rpc_client, &config_payer.signers[0].pubkey()); // config_payer balance
|
||||
check_recent_balance(0, &rpc_client, &process_id); // contract balance
|
||||
check_recent_balance(0, &rpc_client, &bob_pubkey); // recipient balance
|
||||
|
||||
server.close().unwrap();
|
||||
remove_dir_all(ledger_path).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_offline_pay_tx() {
|
||||
let TestValidator {
|
||||
server,
|
||||
leader_data,
|
||||
alice,
|
||||
ledger_path,
|
||||
..
|
||||
} = TestValidator::run();
|
||||
let bob_pubkey = solana_sdk::pubkey::new_rand();
|
||||
|
||||
let (sender, receiver) = channel();
|
||||
run_local_faucet(alice, sender, None);
|
||||
let faucet_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client = RpcClient::new_socket(leader_data.rpc);
|
||||
let default_signer = Keypair::new();
|
||||
let default_offline_signer = Keypair::new();
|
||||
|
||||
let mut config_offline = CliConfig::recent_for_tests();
|
||||
config_offline.json_rpc_url =
|
||||
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
config_offline.signers = vec![&default_offline_signer];
|
||||
let mut config_online = CliConfig::recent_for_tests();
|
||||
config_online.json_rpc_url =
|
||||
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
config_online.signers = vec![&default_signer];
|
||||
assert_ne!(
|
||||
config_offline.signers[0].pubkey(),
|
||||
config_online.signers[0].pubkey()
|
||||
);
|
||||
|
||||
request_and_confirm_airdrop(
|
||||
&rpc_client,
|
||||
&faucet_addr,
|
||||
&config_offline.signers[0].pubkey(),
|
||||
50,
|
||||
&config_offline,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
request_and_confirm_airdrop(
|
||||
&rpc_client,
|
||||
&faucet_addr,
|
||||
&config_online.signers[0].pubkey(),
|
||||
50,
|
||||
&config_offline,
|
||||
)
|
||||
.unwrap();
|
||||
check_recent_balance(50, &rpc_client, &config_offline.signers[0].pubkey());
|
||||
check_recent_balance(50, &rpc_client, &config_online.signers[0].pubkey());
|
||||
|
||||
let (blockhash, _) = rpc_client.get_recent_blockhash().unwrap();
|
||||
config_offline.command = CliCommand::Pay(PayCommand {
|
||||
amount: SpendAmount::Some(10),
|
||||
to: bob_pubkey,
|
||||
blockhash_query: BlockhashQuery::None(blockhash),
|
||||
sign_only: true,
|
||||
..PayCommand::default()
|
||||
});
|
||||
config_offline.output_format = OutputFormat::JsonCompact;
|
||||
let sig_response = process_command(&config_offline).unwrap();
|
||||
|
||||
check_recent_balance(50, &rpc_client, &config_offline.signers[0].pubkey());
|
||||
check_recent_balance(50, &rpc_client, &config_online.signers[0].pubkey());
|
||||
check_recent_balance(0, &rpc_client, &bob_pubkey);
|
||||
|
||||
let sign_only = parse_sign_only_reply_string(&sig_response);
|
||||
assert!(sign_only.has_all_signers());
|
||||
let offline_presigner = sign_only
|
||||
.presigner_of(&config_offline.signers[0].pubkey())
|
||||
.unwrap();
|
||||
let online_pubkey = config_online.signers[0].pubkey();
|
||||
config_online.signers = vec![&offline_presigner];
|
||||
config_online.command = CliCommand::Pay(PayCommand {
|
||||
amount: SpendAmount::Some(10),
|
||||
to: bob_pubkey,
|
||||
blockhash_query: BlockhashQuery::FeeCalculator(blockhash_query::Source::Cluster, blockhash),
|
||||
..PayCommand::default()
|
||||
});
|
||||
process_command(&config_online).unwrap();
|
||||
|
||||
check_recent_balance(40, &rpc_client, &config_offline.signers[0].pubkey());
|
||||
check_recent_balance(50, &rpc_client, &online_pubkey);
|
||||
check_recent_balance(10, &rpc_client, &bob_pubkey);
|
||||
|
||||
server.close().unwrap();
|
||||
remove_dir_all(ledger_path).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_nonced_pay_tx() {
|
||||
solana_logger::setup();
|
||||
|
||||
let TestValidator {
|
||||
server,
|
||||
leader_data,
|
||||
alice,
|
||||
ledger_path,
|
||||
..
|
||||
} = TestValidator::run();
|
||||
let (sender, receiver) = channel();
|
||||
run_local_faucet(alice, sender, None);
|
||||
let faucet_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client = RpcClient::new_socket(leader_data.rpc);
|
||||
let default_signer = Keypair::new();
|
||||
|
||||
let mut config = CliConfig::recent_for_tests();
|
||||
config.json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
config.signers = vec![&default_signer];
|
||||
|
||||
let minimum_nonce_balance = rpc_client
|
||||
.get_minimum_balance_for_rent_exemption(NonceState::size())
|
||||
.unwrap();
|
||||
|
||||
request_and_confirm_airdrop(
|
||||
&rpc_client,
|
||||
&faucet_addr,
|
||||
&config.signers[0].pubkey(),
|
||||
50 + minimum_nonce_balance,
|
||||
&config,
|
||||
)
|
||||
.unwrap();
|
||||
check_recent_balance(
|
||||
50 + minimum_nonce_balance,
|
||||
&rpc_client,
|
||||
&config.signers[0].pubkey(),
|
||||
);
|
||||
|
||||
// Create nonce account
|
||||
let nonce_account = Keypair::new();
|
||||
config.command = CliCommand::CreateNonceAccount {
|
||||
nonce_account: 1,
|
||||
seed: None,
|
||||
nonce_authority: Some(config.signers[0].pubkey()),
|
||||
amount: SpendAmount::Some(minimum_nonce_balance),
|
||||
};
|
||||
config.signers.push(&nonce_account);
|
||||
process_command(&config).unwrap();
|
||||
|
||||
check_recent_balance(50, &rpc_client, &config.signers[0].pubkey());
|
||||
check_recent_balance(minimum_nonce_balance, &rpc_client, &nonce_account.pubkey());
|
||||
|
||||
// Fetch nonce hash
|
||||
let nonce_hash = nonce_utils::get_account_with_commitment(
|
||||
&rpc_client,
|
||||
&nonce_account.pubkey(),
|
||||
CommitmentConfig::recent(),
|
||||
)
|
||||
.and_then(|ref a| nonce_utils::data_from_account(a))
|
||||
.unwrap()
|
||||
.blockhash;
|
||||
|
||||
let bob_pubkey = solana_sdk::pubkey::new_rand();
|
||||
config.signers = vec![&default_signer];
|
||||
config.command = CliCommand::Pay(PayCommand {
|
||||
amount: SpendAmount::Some(10),
|
||||
to: bob_pubkey,
|
||||
blockhash_query: BlockhashQuery::FeeCalculator(
|
||||
blockhash_query::Source::NonceAccount(nonce_account.pubkey()),
|
||||
nonce_hash,
|
||||
),
|
||||
nonce_account: Some(nonce_account.pubkey()),
|
||||
..PayCommand::default()
|
||||
});
|
||||
process_command(&config).expect("failed to process pay command");
|
||||
|
||||
check_recent_balance(40, &rpc_client, &config.signers[0].pubkey());
|
||||
check_recent_balance(10, &rpc_client, &bob_pubkey);
|
||||
|
||||
// Verify that nonce has been used
|
||||
let nonce_hash2 = nonce_utils::get_account_with_commitment(
|
||||
&rpc_client,
|
||||
&nonce_account.pubkey(),
|
||||
CommitmentConfig::recent(),
|
||||
)
|
||||
.and_then(|ref a| nonce_utils::data_from_account(a))
|
||||
.unwrap()
|
||||
.blockhash;
|
||||
assert_ne!(nonce_hash, nonce_hash2);
|
||||
|
||||
server.close().unwrap();
|
||||
remove_dir_all(ledger_path).unwrap();
|
||||
}
|
@@ -1,964 +0,0 @@
|
||||
use serde_json::Value;
|
||||
use solana_cli::{
|
||||
cli::{process_command, CliCommand, CliConfig},
|
||||
program::ProgramCliCommand,
|
||||
};
|
||||
use solana_client::rpc_client::RpcClient;
|
||||
use solana_core::test_validator::TestValidator;
|
||||
use solana_faucet::faucet::run_local_faucet;
|
||||
use solana_sdk::{
|
||||
account_utils::StateMut,
|
||||
bpf_loader,
|
||||
bpf_loader_upgradeable::{self, UpgradeableLoaderState},
|
||||
commitment_config::CommitmentConfig,
|
||||
pubkey::Pubkey,
|
||||
signature::{Keypair, Signer},
|
||||
};
|
||||
use std::{
|
||||
fs::{remove_dir_all, File},
|
||||
io::Read,
|
||||
path::PathBuf,
|
||||
str::FromStr,
|
||||
sync::mpsc::channel,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_cli_program_deploy_non_upgradeable() {
|
||||
solana_logger::setup();
|
||||
|
||||
let mut pathbuf = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
pathbuf.push("tests");
|
||||
pathbuf.push("fixtures");
|
||||
pathbuf.push("noop");
|
||||
pathbuf.set_extension("so");
|
||||
|
||||
let TestValidator {
|
||||
server,
|
||||
leader_data,
|
||||
alice,
|
||||
ledger_path,
|
||||
..
|
||||
} = TestValidator::run();
|
||||
|
||||
let (sender, receiver) = channel();
|
||||
run_local_faucet(alice, sender, None);
|
||||
let faucet_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_socket_with_commitment(leader_data.rpc, CommitmentConfig::recent());
|
||||
|
||||
let mut file = File::open(pathbuf.to_str().unwrap()).unwrap();
|
||||
let mut program_data = Vec::new();
|
||||
file.read_to_end(&mut program_data).unwrap();
|
||||
let minimum_balance_for_rent_exemption = rpc_client
|
||||
.get_minimum_balance_for_rent_exemption(program_data.len())
|
||||
.unwrap();
|
||||
|
||||
let mut config = CliConfig::recent_for_tests();
|
||||
let keypair = Keypair::new();
|
||||
config.json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
config.signers = vec![&keypair];
|
||||
config.command = CliCommand::Airdrop {
|
||||
faucet_host: None,
|
||||
faucet_port: faucet_addr.port(),
|
||||
pubkey: None,
|
||||
lamports: 4 * minimum_balance_for_rent_exemption, // min balance for rent exemption for three programs + leftover for tx processing
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
|
||||
config.command = CliCommand::Deploy {
|
||||
program_location: pathbuf.to_str().unwrap().to_string(),
|
||||
address: None,
|
||||
use_deprecated_loader: false,
|
||||
allow_excessive_balance: false,
|
||||
};
|
||||
let response = process_command(&config);
|
||||
let json: Value = serde_json::from_str(&response.unwrap()).unwrap();
|
||||
let program_id_str = json
|
||||
.as_object()
|
||||
.unwrap()
|
||||
.get("programId")
|
||||
.unwrap()
|
||||
.as_str()
|
||||
.unwrap();
|
||||
let program_id = Pubkey::from_str(&program_id_str).unwrap();
|
||||
let account0 = rpc_client.get_account(&program_id).unwrap();
|
||||
assert_eq!(account0.lamports, minimum_balance_for_rent_exemption);
|
||||
assert_eq!(account0.owner, bpf_loader::id());
|
||||
assert_eq!(account0.executable, true);
|
||||
let mut file = File::open(pathbuf.to_str().unwrap().to_string()).unwrap();
|
||||
let mut elf = Vec::new();
|
||||
file.read_to_end(&mut elf).unwrap();
|
||||
assert_eq!(account0.data, elf);
|
||||
|
||||
// Test custom address
|
||||
let custom_address_keypair = Keypair::new();
|
||||
config.signers = vec![&keypair, &custom_address_keypair];
|
||||
config.command = CliCommand::Deploy {
|
||||
program_location: pathbuf.to_str().unwrap().to_string(),
|
||||
address: Some(1),
|
||||
use_deprecated_loader: false,
|
||||
allow_excessive_balance: false,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
let account1 = rpc_client
|
||||
.get_account(&custom_address_keypair.pubkey())
|
||||
.unwrap();
|
||||
assert_eq!(account1.lamports, minimum_balance_for_rent_exemption);
|
||||
assert_eq!(account1.owner, bpf_loader::id());
|
||||
assert_eq!(account1.executable, true);
|
||||
assert_eq!(account1.data, account0.data);
|
||||
|
||||
// Attempt to redeploy to the same address
|
||||
process_command(&config).unwrap_err();
|
||||
|
||||
// Attempt to deploy to account with excess balance
|
||||
let custom_address_keypair = Keypair::new();
|
||||
config.signers = vec![&custom_address_keypair];
|
||||
config.command = CliCommand::Airdrop {
|
||||
faucet_host: None,
|
||||
faucet_port: faucet_addr.port(),
|
||||
pubkey: None,
|
||||
lamports: 2 * minimum_balance_for_rent_exemption, // Anything over minimum_balance_for_rent_exemption should trigger err
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
config.signers = vec![&keypair, &custom_address_keypair];
|
||||
config.command = CliCommand::Deploy {
|
||||
program_location: pathbuf.to_str().unwrap().to_string(),
|
||||
address: Some(1),
|
||||
use_deprecated_loader: false,
|
||||
allow_excessive_balance: false,
|
||||
};
|
||||
process_command(&config).unwrap_err();
|
||||
|
||||
// Use forcing parameter to deploy to account with excess balance
|
||||
config.command = CliCommand::Deploy {
|
||||
program_location: pathbuf.to_str().unwrap().to_string(),
|
||||
address: Some(1),
|
||||
use_deprecated_loader: false,
|
||||
allow_excessive_balance: true,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
let account2 = rpc_client
|
||||
.get_account(&custom_address_keypair.pubkey())
|
||||
.unwrap();
|
||||
assert_eq!(account2.lamports, 2 * minimum_balance_for_rent_exemption);
|
||||
assert_eq!(account2.owner, bpf_loader::id());
|
||||
assert_eq!(account2.executable, true);
|
||||
assert_eq!(account2.data, account0.data);
|
||||
|
||||
server.close().unwrap();
|
||||
remove_dir_all(ledger_path).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cli_program_deploy_no_authority() {
|
||||
solana_logger::setup();
|
||||
|
||||
let mut pathbuf = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
pathbuf.push("tests");
|
||||
pathbuf.push("fixtures");
|
||||
pathbuf.push("noop");
|
||||
pathbuf.set_extension("so");
|
||||
|
||||
let TestValidator {
|
||||
server,
|
||||
leader_data,
|
||||
alice,
|
||||
ledger_path,
|
||||
..
|
||||
} = TestValidator::run();
|
||||
|
||||
let (sender, receiver) = channel();
|
||||
run_local_faucet(alice, sender, None);
|
||||
let faucet_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_socket_with_commitment(leader_data.rpc, CommitmentConfig::recent());
|
||||
|
||||
let mut file = File::open(pathbuf.to_str().unwrap()).unwrap();
|
||||
let mut program_data = Vec::new();
|
||||
file.read_to_end(&mut program_data).unwrap();
|
||||
let max_len = program_data.len();
|
||||
let minimum_balance_for_programdata = rpc_client
|
||||
.get_minimum_balance_for_rent_exemption(
|
||||
UpgradeableLoaderState::programdata_len(max_len).unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
let minimum_balance_for_program = rpc_client
|
||||
.get_minimum_balance_for_rent_exemption(UpgradeableLoaderState::program_len().unwrap())
|
||||
.unwrap();
|
||||
let upgrade_authority = Keypair::new();
|
||||
|
||||
let mut config = CliConfig::recent_for_tests();
|
||||
let keypair = Keypair::new();
|
||||
config.json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
config.command = CliCommand::Airdrop {
|
||||
faucet_host: None,
|
||||
faucet_port: faucet_addr.port(),
|
||||
pubkey: None,
|
||||
lamports: 100 * minimum_balance_for_programdata + minimum_balance_for_program,
|
||||
};
|
||||
config.signers = vec![&keypair];
|
||||
process_command(&config).unwrap();
|
||||
|
||||
// Deploy a program
|
||||
config.signers = vec![&keypair, &upgrade_authority];
|
||||
config.command = CliCommand::Program(ProgramCliCommand::Deploy {
|
||||
program_location: Some(pathbuf.to_str().unwrap().to_string()),
|
||||
program_signer_index: None,
|
||||
program_pubkey: None,
|
||||
buffer_signer_index: None,
|
||||
buffer_pubkey: None,
|
||||
allow_excessive_balance: false,
|
||||
upgrade_authority_signer_index: 1,
|
||||
is_final: true,
|
||||
max_len: None,
|
||||
});
|
||||
let response = process_command(&config);
|
||||
let json: Value = serde_json::from_str(&response.unwrap()).unwrap();
|
||||
let program_id_str = json
|
||||
.as_object()
|
||||
.unwrap()
|
||||
.get("programId")
|
||||
.unwrap()
|
||||
.as_str()
|
||||
.unwrap();
|
||||
let program_id = Pubkey::from_str(&program_id_str).unwrap();
|
||||
|
||||
// Attempt to upgrade the program
|
||||
config.signers = vec![&keypair, &upgrade_authority];
|
||||
config.command = CliCommand::Program(ProgramCliCommand::Deploy {
|
||||
program_location: Some(pathbuf.to_str().unwrap().to_string()),
|
||||
program_signer_index: None,
|
||||
program_pubkey: Some(program_id),
|
||||
buffer_signer_index: None,
|
||||
buffer_pubkey: None,
|
||||
allow_excessive_balance: false,
|
||||
upgrade_authority_signer_index: 1,
|
||||
is_final: false,
|
||||
max_len: None,
|
||||
});
|
||||
process_command(&config).unwrap_err();
|
||||
|
||||
server.close().unwrap();
|
||||
remove_dir_all(ledger_path).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cli_program_deploy_with_authority() {
|
||||
solana_logger::setup();
|
||||
|
||||
let mut pathbuf = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
pathbuf.push("tests");
|
||||
pathbuf.push("fixtures");
|
||||
pathbuf.push("noop");
|
||||
pathbuf.set_extension("so");
|
||||
|
||||
let TestValidator {
|
||||
server,
|
||||
leader_data,
|
||||
alice,
|
||||
ledger_path,
|
||||
..
|
||||
} = TestValidator::run();
|
||||
|
||||
let (sender, receiver) = channel();
|
||||
run_local_faucet(alice, sender, None);
|
||||
let faucet_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_socket_with_commitment(leader_data.rpc, CommitmentConfig::recent());
|
||||
|
||||
let mut file = File::open(pathbuf.to_str().unwrap()).unwrap();
|
||||
let mut program_data = Vec::new();
|
||||
file.read_to_end(&mut program_data).unwrap();
|
||||
let max_len = program_data.len();
|
||||
let minimum_balance_for_programdata = rpc_client
|
||||
.get_minimum_balance_for_rent_exemption(
|
||||
UpgradeableLoaderState::programdata_len(max_len).unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
let minimum_balance_for_program = rpc_client
|
||||
.get_minimum_balance_for_rent_exemption(UpgradeableLoaderState::program_len().unwrap())
|
||||
.unwrap();
|
||||
let upgrade_authority = Keypair::new();
|
||||
|
||||
let mut config = CliConfig::recent_for_tests();
|
||||
let keypair = Keypair::new();
|
||||
config.json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
config.signers = vec![&keypair];
|
||||
config.command = CliCommand::Airdrop {
|
||||
faucet_host: None,
|
||||
faucet_port: faucet_addr.port(),
|
||||
pubkey: None,
|
||||
lamports: 100 * minimum_balance_for_programdata + minimum_balance_for_program,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
|
||||
// Deploy the upgradeable program with specified program_id
|
||||
let program_keypair = Keypair::new();
|
||||
config.signers = vec![&keypair, &upgrade_authority, &program_keypair];
|
||||
config.command = CliCommand::Program(ProgramCliCommand::Deploy {
|
||||
program_location: Some(pathbuf.to_str().unwrap().to_string()),
|
||||
program_signer_index: Some(2),
|
||||
program_pubkey: Some(program_keypair.pubkey()),
|
||||
buffer_signer_index: None,
|
||||
buffer_pubkey: None,
|
||||
allow_excessive_balance: false,
|
||||
upgrade_authority_signer_index: 1,
|
||||
is_final: false,
|
||||
max_len: Some(max_len),
|
||||
});
|
||||
let response = process_command(&config);
|
||||
let json: Value = serde_json::from_str(&response.unwrap()).unwrap();
|
||||
let program_pubkey_str = json
|
||||
.as_object()
|
||||
.unwrap()
|
||||
.get("programId")
|
||||
.unwrap()
|
||||
.as_str()
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
program_keypair.pubkey(),
|
||||
Pubkey::from_str(&program_pubkey_str).unwrap()
|
||||
);
|
||||
let program_account = rpc_client.get_account(&program_keypair.pubkey()).unwrap();
|
||||
assert_eq!(program_account.lamports, minimum_balance_for_program);
|
||||
assert_eq!(program_account.owner, bpf_loader_upgradeable::id());
|
||||
assert_eq!(program_account.executable, true);
|
||||
let (programdata_pubkey, _) = Pubkey::find_program_address(
|
||||
&[program_keypair.pubkey().as_ref()],
|
||||
&bpf_loader_upgradeable::id(),
|
||||
);
|
||||
let programdata_account = rpc_client.get_account(&programdata_pubkey).unwrap();
|
||||
assert_eq!(
|
||||
programdata_account.lamports,
|
||||
minimum_balance_for_programdata
|
||||
);
|
||||
assert_eq!(programdata_account.owner, bpf_loader_upgradeable::id());
|
||||
assert_eq!(programdata_account.executable, false);
|
||||
assert_eq!(
|
||||
programdata_account.data[UpgradeableLoaderState::programdata_data_offset().unwrap()..],
|
||||
program_data[..]
|
||||
);
|
||||
|
||||
// Deploy the upgradeable program
|
||||
config.signers = vec![&keypair, &upgrade_authority];
|
||||
config.command = CliCommand::Program(ProgramCliCommand::Deploy {
|
||||
program_location: Some(pathbuf.to_str().unwrap().to_string()),
|
||||
program_signer_index: None,
|
||||
program_pubkey: None,
|
||||
buffer_signer_index: None,
|
||||
buffer_pubkey: None,
|
||||
allow_excessive_balance: false,
|
||||
upgrade_authority_signer_index: 1,
|
||||
is_final: false,
|
||||
max_len: Some(max_len),
|
||||
});
|
||||
let response = process_command(&config);
|
||||
let json: Value = serde_json::from_str(&response.unwrap()).unwrap();
|
||||
let program_pubkey_str = json
|
||||
.as_object()
|
||||
.unwrap()
|
||||
.get("programId")
|
||||
.unwrap()
|
||||
.as_str()
|
||||
.unwrap();
|
||||
let program_pubkey = Pubkey::from_str(&program_pubkey_str).unwrap();
|
||||
let program_account = rpc_client.get_account(&program_pubkey).unwrap();
|
||||
assert_eq!(program_account.lamports, minimum_balance_for_program);
|
||||
assert_eq!(program_account.owner, bpf_loader_upgradeable::id());
|
||||
assert_eq!(program_account.executable, true);
|
||||
let (programdata_pubkey, _) =
|
||||
Pubkey::find_program_address(&[program_pubkey.as_ref()], &bpf_loader_upgradeable::id());
|
||||
let programdata_account = rpc_client.get_account(&programdata_pubkey).unwrap();
|
||||
assert_eq!(
|
||||
programdata_account.lamports,
|
||||
minimum_balance_for_programdata
|
||||
);
|
||||
assert_eq!(programdata_account.owner, bpf_loader_upgradeable::id());
|
||||
assert_eq!(programdata_account.executable, false);
|
||||
assert_eq!(
|
||||
programdata_account.data[UpgradeableLoaderState::programdata_data_offset().unwrap()..],
|
||||
program_data[..]
|
||||
);
|
||||
|
||||
// Upgrade the program
|
||||
config.signers = vec![&keypair, &upgrade_authority];
|
||||
config.command = CliCommand::Program(ProgramCliCommand::Deploy {
|
||||
program_location: Some(pathbuf.to_str().unwrap().to_string()),
|
||||
program_signer_index: None,
|
||||
program_pubkey: Some(program_pubkey),
|
||||
buffer_signer_index: None,
|
||||
buffer_pubkey: None,
|
||||
allow_excessive_balance: false,
|
||||
upgrade_authority_signer_index: 1,
|
||||
is_final: false,
|
||||
max_len: Some(max_len),
|
||||
});
|
||||
process_command(&config).unwrap();
|
||||
let program_account = rpc_client.get_account(&program_pubkey).unwrap();
|
||||
assert_eq!(program_account.lamports, minimum_balance_for_program);
|
||||
assert_eq!(program_account.owner, bpf_loader_upgradeable::id());
|
||||
assert_eq!(program_account.executable, true);
|
||||
let (programdata_pubkey, _) =
|
||||
Pubkey::find_program_address(&[program_pubkey.as_ref()], &bpf_loader_upgradeable::id());
|
||||
let programdata_account = rpc_client.get_account(&programdata_pubkey).unwrap();
|
||||
assert_eq!(
|
||||
programdata_account.lamports,
|
||||
minimum_balance_for_programdata
|
||||
);
|
||||
assert_eq!(programdata_account.owner, bpf_loader_upgradeable::id());
|
||||
assert_eq!(programdata_account.executable, false);
|
||||
assert_eq!(
|
||||
programdata_account.data[UpgradeableLoaderState::programdata_data_offset().unwrap()..],
|
||||
program_data[..]
|
||||
);
|
||||
|
||||
// Set a new authority
|
||||
let new_upgrade_authority = Keypair::new();
|
||||
config.signers = vec![&keypair, &upgrade_authority];
|
||||
config.command = CliCommand::Program(ProgramCliCommand::SetUpgradeAuthority {
|
||||
program_pubkey,
|
||||
upgrade_authority_index: Some(1),
|
||||
new_upgrade_authority: Some(new_upgrade_authority.pubkey()),
|
||||
});
|
||||
let response = process_command(&config);
|
||||
let json: Value = serde_json::from_str(&response.unwrap()).unwrap();
|
||||
let new_upgrade_authority_str = json
|
||||
.as_object()
|
||||
.unwrap()
|
||||
.get("authority")
|
||||
.unwrap()
|
||||
.as_str()
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
Pubkey::from_str(&new_upgrade_authority_str).unwrap(),
|
||||
new_upgrade_authority.pubkey()
|
||||
);
|
||||
|
||||
// Upgrade with new authority
|
||||
config.signers = vec![&keypair, &new_upgrade_authority];
|
||||
config.command = CliCommand::Program(ProgramCliCommand::Deploy {
|
||||
program_location: Some(pathbuf.to_str().unwrap().to_string()),
|
||||
program_signer_index: None,
|
||||
program_pubkey: Some(program_pubkey),
|
||||
buffer_signer_index: None,
|
||||
buffer_pubkey: None,
|
||||
allow_excessive_balance: false,
|
||||
upgrade_authority_signer_index: 1,
|
||||
is_final: false,
|
||||
max_len: None,
|
||||
});
|
||||
process_command(&config).unwrap();
|
||||
let program_account = rpc_client.get_account(&program_pubkey).unwrap();
|
||||
assert_eq!(program_account.lamports, minimum_balance_for_program);
|
||||
assert_eq!(program_account.owner, bpf_loader_upgradeable::id());
|
||||
assert_eq!(program_account.executable, true);
|
||||
let (programdata_pubkey, _) =
|
||||
Pubkey::find_program_address(&[program_pubkey.as_ref()], &bpf_loader_upgradeable::id());
|
||||
let programdata_account = rpc_client.get_account(&programdata_pubkey).unwrap();
|
||||
assert_eq!(
|
||||
programdata_account.lamports,
|
||||
minimum_balance_for_programdata
|
||||
);
|
||||
assert_eq!(programdata_account.owner, bpf_loader_upgradeable::id());
|
||||
assert_eq!(programdata_account.executable, false);
|
||||
assert_eq!(
|
||||
programdata_account.data[UpgradeableLoaderState::programdata_data_offset().unwrap()..],
|
||||
program_data[..]
|
||||
);
|
||||
|
||||
// Set no authority
|
||||
config.signers = vec![&keypair, &new_upgrade_authority];
|
||||
config.command = CliCommand::Program(ProgramCliCommand::SetUpgradeAuthority {
|
||||
program_pubkey,
|
||||
upgrade_authority_index: Some(1),
|
||||
new_upgrade_authority: None,
|
||||
});
|
||||
let response = process_command(&config);
|
||||
let json: Value = serde_json::from_str(&response.unwrap()).unwrap();
|
||||
let new_upgrade_authority_str = json
|
||||
.as_object()
|
||||
.unwrap()
|
||||
.get("authority")
|
||||
.unwrap()
|
||||
.as_str()
|
||||
.unwrap();
|
||||
assert_eq!(new_upgrade_authority_str, "none");
|
||||
|
||||
// Upgrade with no authority
|
||||
config.signers = vec![&keypair, &new_upgrade_authority];
|
||||
config.command = CliCommand::Program(ProgramCliCommand::Deploy {
|
||||
program_location: Some(pathbuf.to_str().unwrap().to_string()),
|
||||
program_signer_index: None,
|
||||
program_pubkey: Some(program_pubkey),
|
||||
buffer_signer_index: None,
|
||||
buffer_pubkey: None,
|
||||
allow_excessive_balance: false,
|
||||
upgrade_authority_signer_index: 1,
|
||||
is_final: false,
|
||||
max_len: None,
|
||||
});
|
||||
process_command(&config).unwrap_err();
|
||||
|
||||
// deploy with finality
|
||||
config.signers = vec![&keypair, &new_upgrade_authority];
|
||||
config.command = CliCommand::Program(ProgramCliCommand::Deploy {
|
||||
program_location: Some(pathbuf.to_str().unwrap().to_string()),
|
||||
program_signer_index: None,
|
||||
program_pubkey: None,
|
||||
buffer_signer_index: None,
|
||||
buffer_pubkey: None,
|
||||
allow_excessive_balance: false,
|
||||
upgrade_authority_signer_index: 1,
|
||||
is_final: true,
|
||||
max_len: None,
|
||||
});
|
||||
let response = process_command(&config);
|
||||
let json: Value = serde_json::from_str(&response.unwrap()).unwrap();
|
||||
let program_pubkey_str = json
|
||||
.as_object()
|
||||
.unwrap()
|
||||
.get("programId")
|
||||
.unwrap()
|
||||
.as_str()
|
||||
.unwrap();
|
||||
let program_pubkey = Pubkey::from_str(&program_pubkey_str).unwrap();
|
||||
let (programdata_pubkey, _) =
|
||||
Pubkey::find_program_address(&[program_pubkey.as_ref()], &bpf_loader_upgradeable::id());
|
||||
let programdata_account = rpc_client.get_account(&programdata_pubkey).unwrap();
|
||||
if let UpgradeableLoaderState::ProgramData {
|
||||
slot: _,
|
||||
upgrade_authority_address,
|
||||
} = programdata_account.state().unwrap()
|
||||
{
|
||||
assert_eq!(upgrade_authority_address, None);
|
||||
} else {
|
||||
panic!("not a buffer account");
|
||||
}
|
||||
|
||||
server.close().unwrap();
|
||||
remove_dir_all(ledger_path).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cli_program_write_buffer() {
|
||||
solana_logger::setup();
|
||||
|
||||
let mut pathbuf = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
pathbuf.push("tests");
|
||||
pathbuf.push("fixtures");
|
||||
pathbuf.push("noop");
|
||||
pathbuf.set_extension("so");
|
||||
|
||||
let TestValidator {
|
||||
server,
|
||||
leader_data,
|
||||
alice,
|
||||
ledger_path,
|
||||
..
|
||||
} = TestValidator::run();
|
||||
|
||||
let (sender, receiver) = channel();
|
||||
run_local_faucet(alice, sender, None);
|
||||
let faucet_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_socket_with_commitment(leader_data.rpc, CommitmentConfig::recent());
|
||||
|
||||
let mut file = File::open(pathbuf.to_str().unwrap()).unwrap();
|
||||
let mut program_data = Vec::new();
|
||||
file.read_to_end(&mut program_data).unwrap();
|
||||
let max_len = program_data.len();
|
||||
let minimum_balance_for_buffer = rpc_client
|
||||
.get_minimum_balance_for_rent_exemption(
|
||||
UpgradeableLoaderState::programdata_len(max_len).unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
let minimum_balance_for_buffer_default = rpc_client
|
||||
.get_minimum_balance_for_rent_exemption(
|
||||
UpgradeableLoaderState::programdata_len(max_len * 2).unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut config = CliConfig::recent_for_tests();
|
||||
let keypair = Keypair::new();
|
||||
config.json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
config.signers = vec![&keypair];
|
||||
config.command = CliCommand::Airdrop {
|
||||
faucet_host: None,
|
||||
faucet_port: faucet_addr.port(),
|
||||
pubkey: None,
|
||||
lamports: 100 * minimum_balance_for_buffer,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
|
||||
// Write a buffer with default params
|
||||
config.signers = vec![&keypair];
|
||||
config.command = CliCommand::Program(ProgramCliCommand::WriteBuffer {
|
||||
program_location: pathbuf.to_str().unwrap().to_string(),
|
||||
buffer_signer_index: None,
|
||||
buffer_pubkey: None,
|
||||
buffer_authority_signer_index: None,
|
||||
max_len: None,
|
||||
});
|
||||
let response = process_command(&config);
|
||||
let json: Value = serde_json::from_str(&response.unwrap()).unwrap();
|
||||
let buffer_pubkey_str = json
|
||||
.as_object()
|
||||
.unwrap()
|
||||
.get("buffer")
|
||||
.unwrap()
|
||||
.as_str()
|
||||
.unwrap();
|
||||
let new_buffer_pubkey = Pubkey::from_str(&buffer_pubkey_str).unwrap();
|
||||
let buffer_account = rpc_client.get_account(&new_buffer_pubkey).unwrap();
|
||||
assert_eq!(buffer_account.lamports, minimum_balance_for_buffer_default);
|
||||
assert_eq!(buffer_account.owner, bpf_loader_upgradeable::id());
|
||||
if let UpgradeableLoaderState::Buffer { authority_address } = buffer_account.state().unwrap() {
|
||||
assert_eq!(authority_address, Some(keypair.pubkey()));
|
||||
} else {
|
||||
panic!("not a buffer account");
|
||||
}
|
||||
assert_eq!(
|
||||
buffer_account.data[UpgradeableLoaderState::buffer_data_offset().unwrap()..],
|
||||
program_data[..]
|
||||
);
|
||||
|
||||
// Specify buffer keypair and max_len
|
||||
let buffer_keypair = Keypair::new();
|
||||
config.signers = vec![&keypair, &buffer_keypair];
|
||||
config.command = CliCommand::Program(ProgramCliCommand::WriteBuffer {
|
||||
program_location: pathbuf.to_str().unwrap().to_string(),
|
||||
buffer_signer_index: Some(1),
|
||||
buffer_pubkey: Some(buffer_keypair.pubkey()),
|
||||
buffer_authority_signer_index: None,
|
||||
max_len: Some(max_len),
|
||||
});
|
||||
let response = process_command(&config);
|
||||
let json: Value = serde_json::from_str(&response.unwrap()).unwrap();
|
||||
let buffer_pubkey_str = json
|
||||
.as_object()
|
||||
.unwrap()
|
||||
.get("buffer")
|
||||
.unwrap()
|
||||
.as_str()
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
buffer_keypair.pubkey(),
|
||||
Pubkey::from_str(&buffer_pubkey_str).unwrap()
|
||||
);
|
||||
let buffer_account = rpc_client.get_account(&buffer_keypair.pubkey()).unwrap();
|
||||
assert_eq!(buffer_account.lamports, minimum_balance_for_buffer);
|
||||
assert_eq!(buffer_account.owner, bpf_loader_upgradeable::id());
|
||||
if let UpgradeableLoaderState::Buffer { authority_address } = buffer_account.state().unwrap() {
|
||||
assert_eq!(authority_address, Some(keypair.pubkey()));
|
||||
} else {
|
||||
panic!("not a buffer account");
|
||||
}
|
||||
assert_eq!(
|
||||
buffer_account.data[UpgradeableLoaderState::buffer_data_offset().unwrap()..],
|
||||
program_data[..]
|
||||
);
|
||||
|
||||
// Specify buffer authority
|
||||
let buffer_keypair = Keypair::new();
|
||||
let authority_keypair = Keypair::new();
|
||||
config.signers = vec![&keypair, &buffer_keypair, &authority_keypair];
|
||||
config.command = CliCommand::Program(ProgramCliCommand::WriteBuffer {
|
||||
program_location: pathbuf.to_str().unwrap().to_string(),
|
||||
buffer_signer_index: Some(1),
|
||||
buffer_pubkey: Some(buffer_keypair.pubkey()),
|
||||
buffer_authority_signer_index: Some(2),
|
||||
max_len: None,
|
||||
});
|
||||
let response = process_command(&config);
|
||||
let json: Value = serde_json::from_str(&response.unwrap()).unwrap();
|
||||
let buffer_pubkey_str = json
|
||||
.as_object()
|
||||
.unwrap()
|
||||
.get("buffer")
|
||||
.unwrap()
|
||||
.as_str()
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
buffer_keypair.pubkey(),
|
||||
Pubkey::from_str(&buffer_pubkey_str).unwrap()
|
||||
);
|
||||
let buffer_account = rpc_client.get_account(&buffer_keypair.pubkey()).unwrap();
|
||||
assert_eq!(buffer_account.lamports, minimum_balance_for_buffer_default);
|
||||
assert_eq!(buffer_account.owner, bpf_loader_upgradeable::id());
|
||||
if let UpgradeableLoaderState::Buffer { authority_address } = buffer_account.state().unwrap() {
|
||||
assert_eq!(authority_address, Some(authority_keypair.pubkey()));
|
||||
} else {
|
||||
panic!("not a buffer account");
|
||||
}
|
||||
assert_eq!(
|
||||
buffer_account.data[UpgradeableLoaderState::buffer_data_offset().unwrap()..],
|
||||
program_data[..]
|
||||
);
|
||||
|
||||
// Specify authority only
|
||||
let buffer_keypair = Keypair::new();
|
||||
let authority_keypair = Keypair::new();
|
||||
config.signers = vec![&keypair, &buffer_keypair, &authority_keypair];
|
||||
config.command = CliCommand::Program(ProgramCliCommand::WriteBuffer {
|
||||
program_location: pathbuf.to_str().unwrap().to_string(),
|
||||
buffer_signer_index: None,
|
||||
buffer_pubkey: None,
|
||||
buffer_authority_signer_index: Some(2),
|
||||
max_len: None,
|
||||
});
|
||||
let response = process_command(&config);
|
||||
let json: Value = serde_json::from_str(&response.unwrap()).unwrap();
|
||||
let buffer_pubkey_str = json
|
||||
.as_object()
|
||||
.unwrap()
|
||||
.get("buffer")
|
||||
.unwrap()
|
||||
.as_str()
|
||||
.unwrap();
|
||||
let buffer_pubkey = Pubkey::from_str(&buffer_pubkey_str).unwrap();
|
||||
let buffer_account = rpc_client.get_account(&buffer_pubkey).unwrap();
|
||||
assert_eq!(buffer_account.lamports, minimum_balance_for_buffer_default);
|
||||
assert_eq!(buffer_account.owner, bpf_loader_upgradeable::id());
|
||||
if let UpgradeableLoaderState::Buffer { authority_address } = buffer_account.state().unwrap() {
|
||||
assert_eq!(authority_address, Some(authority_keypair.pubkey()));
|
||||
} else {
|
||||
panic!("not a buffer account");
|
||||
}
|
||||
assert_eq!(
|
||||
buffer_account.data[UpgradeableLoaderState::buffer_data_offset().unwrap()..],
|
||||
program_data[..]
|
||||
);
|
||||
|
||||
server.close().unwrap();
|
||||
remove_dir_all(ledger_path).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cli_program_set_buffer_authority() {
|
||||
solana_logger::setup();
|
||||
|
||||
let mut pathbuf = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
pathbuf.push("tests");
|
||||
pathbuf.push("fixtures");
|
||||
pathbuf.push("noop");
|
||||
pathbuf.set_extension("so");
|
||||
|
||||
let TestValidator {
|
||||
server,
|
||||
leader_data,
|
||||
alice,
|
||||
ledger_path,
|
||||
..
|
||||
} = TestValidator::run();
|
||||
|
||||
let (sender, receiver) = channel();
|
||||
run_local_faucet(alice, sender, None);
|
||||
let faucet_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_socket_with_commitment(leader_data.rpc, CommitmentConfig::recent());
|
||||
|
||||
let mut file = File::open(pathbuf.to_str().unwrap()).unwrap();
|
||||
let mut program_data = Vec::new();
|
||||
file.read_to_end(&mut program_data).unwrap();
|
||||
let max_len = program_data.len();
|
||||
let minimum_balance_for_buffer = rpc_client
|
||||
.get_minimum_balance_for_rent_exemption(
|
||||
UpgradeableLoaderState::programdata_len(max_len).unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut config = CliConfig::recent_for_tests();
|
||||
let keypair = Keypair::new();
|
||||
config.json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
config.signers = vec![&keypair];
|
||||
config.command = CliCommand::Airdrop {
|
||||
faucet_host: None,
|
||||
faucet_port: faucet_addr.port(),
|
||||
pubkey: None,
|
||||
lamports: 100 * minimum_balance_for_buffer,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
|
||||
// Write a buffer
|
||||
let buffer_keypair = Keypair::new();
|
||||
config.signers = vec![&keypair, &buffer_keypair];
|
||||
config.command = CliCommand::Program(ProgramCliCommand::WriteBuffer {
|
||||
program_location: pathbuf.to_str().unwrap().to_string(),
|
||||
buffer_signer_index: Some(1),
|
||||
buffer_pubkey: Some(buffer_keypair.pubkey()),
|
||||
buffer_authority_signer_index: None,
|
||||
max_len: None,
|
||||
});
|
||||
process_command(&config).unwrap();
|
||||
let buffer_account = rpc_client.get_account(&buffer_keypair.pubkey()).unwrap();
|
||||
if let UpgradeableLoaderState::Buffer { authority_address } = buffer_account.state().unwrap() {
|
||||
assert_eq!(authority_address, Some(keypair.pubkey()));
|
||||
} else {
|
||||
panic!("not a buffer account");
|
||||
}
|
||||
|
||||
// Set new authority
|
||||
let new_buffer_authority = Keypair::new();
|
||||
config.signers = vec![&keypair, &buffer_keypair];
|
||||
config.command = CliCommand::Program(ProgramCliCommand::SetBufferAuthority {
|
||||
buffer_pubkey: buffer_keypair.pubkey(),
|
||||
buffer_authority_index: Some(0),
|
||||
new_buffer_authority: new_buffer_authority.pubkey(),
|
||||
});
|
||||
let response = process_command(&config);
|
||||
let json: Value = serde_json::from_str(&response.unwrap()).unwrap();
|
||||
let new_buffer_authority_str = json
|
||||
.as_object()
|
||||
.unwrap()
|
||||
.get("authority")
|
||||
.unwrap()
|
||||
.as_str()
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
Pubkey::from_str(&new_buffer_authority_str).unwrap(),
|
||||
new_buffer_authority.pubkey()
|
||||
);
|
||||
let buffer_account = rpc_client.get_account(&buffer_keypair.pubkey()).unwrap();
|
||||
if let UpgradeableLoaderState::Buffer { authority_address } = buffer_account.state().unwrap() {
|
||||
assert_eq!(authority_address, Some(new_buffer_authority.pubkey()));
|
||||
} else {
|
||||
panic!("not a buffer account");
|
||||
}
|
||||
|
||||
// Set authority to buffer
|
||||
config.signers = vec![&keypair, &new_buffer_authority];
|
||||
config.command = CliCommand::Program(ProgramCliCommand::SetBufferAuthority {
|
||||
buffer_pubkey: buffer_keypair.pubkey(),
|
||||
buffer_authority_index: Some(1),
|
||||
new_buffer_authority: buffer_keypair.pubkey(),
|
||||
});
|
||||
let response = process_command(&config);
|
||||
let json: Value = serde_json::from_str(&response.unwrap()).unwrap();
|
||||
let buffer_authority_str = json
|
||||
.as_object()
|
||||
.unwrap()
|
||||
.get("authority")
|
||||
.unwrap()
|
||||
.as_str()
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
Pubkey::from_str(&buffer_authority_str).unwrap(),
|
||||
buffer_keypair.pubkey()
|
||||
);
|
||||
let buffer_account = rpc_client.get_account(&buffer_keypair.pubkey()).unwrap();
|
||||
if let UpgradeableLoaderState::Buffer { authority_address } = buffer_account.state().unwrap() {
|
||||
assert_eq!(authority_address, Some(buffer_keypair.pubkey()));
|
||||
} else {
|
||||
panic!("not a buffer account");
|
||||
}
|
||||
|
||||
server.close().unwrap();
|
||||
remove_dir_all(ledger_path).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cli_program_mismatch_buffer_authority() {
|
||||
solana_logger::setup();
|
||||
|
||||
let mut pathbuf = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
pathbuf.push("tests");
|
||||
pathbuf.push("fixtures");
|
||||
pathbuf.push("noop");
|
||||
pathbuf.set_extension("so");
|
||||
|
||||
let TestValidator {
|
||||
server,
|
||||
leader_data,
|
||||
alice,
|
||||
ledger_path,
|
||||
..
|
||||
} = TestValidator::run();
|
||||
|
||||
let (sender, receiver) = channel();
|
||||
run_local_faucet(alice, sender, None);
|
||||
let faucet_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_socket_with_commitment(leader_data.rpc, CommitmentConfig::recent());
|
||||
|
||||
let mut file = File::open(pathbuf.to_str().unwrap()).unwrap();
|
||||
let mut program_data = Vec::new();
|
||||
file.read_to_end(&mut program_data).unwrap();
|
||||
let max_len = program_data.len();
|
||||
let minimum_balance_for_buffer = rpc_client
|
||||
.get_minimum_balance_for_rent_exemption(
|
||||
UpgradeableLoaderState::programdata_len(max_len).unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut config = CliConfig::recent_for_tests();
|
||||
let keypair = Keypair::new();
|
||||
config.json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
config.signers = vec![&keypair];
|
||||
config.command = CliCommand::Airdrop {
|
||||
faucet_host: None,
|
||||
faucet_port: faucet_addr.port(),
|
||||
pubkey: None,
|
||||
lamports: 100 * minimum_balance_for_buffer,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
|
||||
// Write a buffer
|
||||
let buffer_authority = Keypair::new();
|
||||
let buffer_keypair = Keypair::new();
|
||||
config.signers = vec![&keypair, &buffer_keypair, &buffer_authority];
|
||||
config.command = CliCommand::Program(ProgramCliCommand::WriteBuffer {
|
||||
program_location: pathbuf.to_str().unwrap().to_string(),
|
||||
buffer_signer_index: Some(1),
|
||||
buffer_pubkey: Some(buffer_keypair.pubkey()),
|
||||
buffer_authority_signer_index: Some(2),
|
||||
max_len: None,
|
||||
});
|
||||
process_command(&config).unwrap();
|
||||
let buffer_account = rpc_client.get_account(&buffer_keypair.pubkey()).unwrap();
|
||||
if let UpgradeableLoaderState::Buffer { authority_address } = buffer_account.state().unwrap() {
|
||||
assert_eq!(authority_address, Some(buffer_authority.pubkey()));
|
||||
} else {
|
||||
panic!("not a buffer account");
|
||||
}
|
||||
|
||||
// Attempt to deploy with mismatched authority
|
||||
let upgrade_authority = Keypair::new();
|
||||
config.signers = vec![&keypair, &upgrade_authority];
|
||||
config.command = CliCommand::Program(ProgramCliCommand::Deploy {
|
||||
program_location: Some(pathbuf.to_str().unwrap().to_string()),
|
||||
program_signer_index: None,
|
||||
program_pubkey: None,
|
||||
buffer_signer_index: None,
|
||||
buffer_pubkey: Some(buffer_keypair.pubkey()),
|
||||
allow_excessive_balance: false,
|
||||
upgrade_authority_signer_index: 1,
|
||||
is_final: true,
|
||||
max_len: None,
|
||||
});
|
||||
process_command(&config).unwrap_err();
|
||||
|
||||
// Attempt to deploy matched authority
|
||||
config.signers = vec![&keypair, &buffer_authority];
|
||||
config.command = CliCommand::Program(ProgramCliCommand::Deploy {
|
||||
program_location: Some(pathbuf.to_str().unwrap().to_string()),
|
||||
program_signer_index: None,
|
||||
program_pubkey: None,
|
||||
buffer_signer_index: None,
|
||||
buffer_pubkey: Some(buffer_keypair.pubkey()),
|
||||
allow_excessive_balance: false,
|
||||
upgrade_authority_signer_index: 1,
|
||||
is_final: true,
|
||||
max_len: None,
|
||||
});
|
||||
process_command(&config).unwrap();
|
||||
|
||||
server.close().unwrap();
|
||||
remove_dir_all(ledger_path).unwrap();
|
||||
}
|
@@ -32,12 +32,12 @@ fn test_cli_request_airdrop() {
|
||||
let sig_response = process_command(&bob_config);
|
||||
sig_response.unwrap();
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_socket_with_commitment(leader_data.rpc, CommitmentConfig::recent());
|
||||
let rpc_client = RpcClient::new_socket(leader_data.rpc);
|
||||
|
||||
let balance = rpc_client
|
||||
.get_balance(&bob_config.signers[0].pubkey())
|
||||
.unwrap();
|
||||
.get_balance_with_commitment(&bob_config.signers[0].pubkey(), CommitmentConfig::recent())
|
||||
.unwrap()
|
||||
.value;
|
||||
assert_eq!(balance, 50);
|
||||
|
||||
server.close().unwrap();
|
||||
|
@@ -37,8 +37,7 @@ fn test_stake_delegation_force() {
|
||||
run_local_faucet(alice, sender, None);
|
||||
let faucet_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_socket_with_commitment(leader_data.rpc, CommitmentConfig::recent());
|
||||
let rpc_client = RpcClient::new_socket(leader_data.rpc);
|
||||
let default_signer = Keypair::new();
|
||||
|
||||
let mut config = CliConfig::recent_for_tests();
|
||||
@@ -135,8 +134,7 @@ fn test_seed_stake_delegation_and_deactivation() {
|
||||
run_local_faucet(alice, sender, None);
|
||||
let faucet_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_socket_with_commitment(leader_data.rpc, CommitmentConfig::recent());
|
||||
let rpc_client = RpcClient::new_socket(leader_data.rpc);
|
||||
|
||||
let validator_keypair = keypair_from_seed(&[0u8; 32]).unwrap();
|
||||
let mut config_validator = CliConfig::recent_for_tests();
|
||||
@@ -225,8 +223,7 @@ fn test_stake_delegation_and_deactivation() {
|
||||
run_local_faucet(alice, sender, None);
|
||||
let faucet_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_socket_with_commitment(leader_data.rpc, CommitmentConfig::recent());
|
||||
let rpc_client = RpcClient::new_socket(leader_data.rpc);
|
||||
let validator_keypair = Keypair::new();
|
||||
|
||||
let mut config_validator = CliConfig::recent_for_tests();
|
||||
@@ -311,8 +308,7 @@ fn test_offline_stake_delegation_and_deactivation() {
|
||||
run_local_faucet(alice, sender, None);
|
||||
let faucet_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_socket_with_commitment(leader_data.rpc, CommitmentConfig::recent());
|
||||
let rpc_client = RpcClient::new_socket(leader_data.rpc);
|
||||
|
||||
let mut config_validator = CliConfig::recent_for_tests();
|
||||
config_validator.json_rpc_url =
|
||||
@@ -455,8 +451,7 @@ fn test_nonced_stake_delegation_and_deactivation() {
|
||||
run_local_faucet(alice, sender, None);
|
||||
let faucet_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_socket_with_commitment(leader_data.rpc, CommitmentConfig::recent());
|
||||
let rpc_client = RpcClient::new_socket(leader_data.rpc);
|
||||
|
||||
let config_keypair = keypair_from_seed(&[0u8; 32]).unwrap();
|
||||
let mut config = CliConfig::recent_for_tests();
|
||||
@@ -578,8 +573,7 @@ fn test_stake_authorize() {
|
||||
run_local_faucet(alice, sender, None);
|
||||
let faucet_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_socket_with_commitment(leader_data.rpc, CommitmentConfig::recent());
|
||||
let rpc_client = RpcClient::new_socket(leader_data.rpc);
|
||||
let default_signer = Keypair::new();
|
||||
|
||||
let mut config = CliConfig::recent_for_tests();
|
||||
@@ -645,10 +639,13 @@ fn test_stake_authorize() {
|
||||
nonce_account: None,
|
||||
nonce_authority: 0,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
let stake_account = rpc_client.get_account(&stake_account_pubkey).unwrap();
|
||||
let stake_account = rpc_client
|
||||
.get_account_with_commitment(&stake_account_pubkey, CommitmentConfig::recent())
|
||||
.unwrap()
|
||||
.value
|
||||
.unwrap();
|
||||
let stake_state: StakeState = stake_account.state().unwrap();
|
||||
let current_authority = match stake_state {
|
||||
StakeState::Initialized(meta) => meta.authorized.staker,
|
||||
@@ -673,10 +670,13 @@ fn test_stake_authorize() {
|
||||
nonce_account: None,
|
||||
nonce_authority: 0,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
let stake_account = rpc_client.get_account(&stake_account_pubkey).unwrap();
|
||||
let stake_account = rpc_client
|
||||
.get_account_with_commitment(&stake_account_pubkey, CommitmentConfig::recent())
|
||||
.unwrap()
|
||||
.value
|
||||
.unwrap();
|
||||
let stake_state: StakeState = stake_account.state().unwrap();
|
||||
let (current_staker, current_withdrawer) = match stake_state {
|
||||
StakeState::Initialized(meta) => (meta.authorized.staker, meta.authorized.withdrawer),
|
||||
@@ -696,10 +696,13 @@ fn test_stake_authorize() {
|
||||
nonce_account: None,
|
||||
nonce_authority: 0,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
let stake_account = rpc_client.get_account(&stake_account_pubkey).unwrap();
|
||||
let stake_account = rpc_client
|
||||
.get_account_with_commitment(&stake_account_pubkey, CommitmentConfig::recent())
|
||||
.unwrap()
|
||||
.value
|
||||
.unwrap();
|
||||
let stake_state: StakeState = stake_account.state().unwrap();
|
||||
let current_authority = match stake_state {
|
||||
StakeState::Initialized(meta) => meta.authorized.staker,
|
||||
@@ -710,7 +713,10 @@ fn test_stake_authorize() {
|
||||
// Offline assignment of new nonced stake authority
|
||||
let nonced_authority = Keypair::new();
|
||||
let nonced_authority_pubkey = nonced_authority.pubkey();
|
||||
let (blockhash, _) = rpc_client.get_recent_blockhash().unwrap();
|
||||
let (blockhash, _, _) = rpc_client
|
||||
.get_recent_blockhash_with_commitment(CommitmentConfig::recent())
|
||||
.unwrap()
|
||||
.value;
|
||||
config_offline.command = CliCommand::StakeAuthorize {
|
||||
stake_account_pubkey,
|
||||
new_authorizations: vec![(StakeAuthorize::Staker, nonced_authority_pubkey, 0)],
|
||||
@@ -719,7 +725,6 @@ fn test_stake_authorize() {
|
||||
nonce_account: None,
|
||||
nonce_authority: 0,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
};
|
||||
config_offline.output_format = OutputFormat::JsonCompact;
|
||||
let sign_reply = process_command(&config_offline).unwrap();
|
||||
@@ -735,10 +740,13 @@ fn test_stake_authorize() {
|
||||
nonce_account: None,
|
||||
nonce_authority: 0,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
let stake_account = rpc_client.get_account(&stake_account_pubkey).unwrap();
|
||||
let stake_account = rpc_client
|
||||
.get_account_with_commitment(&stake_account_pubkey, CommitmentConfig::recent())
|
||||
.unwrap()
|
||||
.value
|
||||
.unwrap();
|
||||
let stake_state: StakeState = stake_account.state().unwrap();
|
||||
let current_authority = match stake_state {
|
||||
StakeState::Initialized(meta) => meta.authorized.staker,
|
||||
@@ -782,7 +790,6 @@ fn test_stake_authorize() {
|
||||
nonce_account: Some(nonce_account.pubkey()),
|
||||
nonce_authority: 0,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
};
|
||||
let sign_reply = process_command(&config_offline).unwrap();
|
||||
let sign_only = parse_sign_only_reply_string(&sign_reply);
|
||||
@@ -802,10 +809,13 @@ fn test_stake_authorize() {
|
||||
nonce_account: Some(nonce_account.pubkey()),
|
||||
nonce_authority: 0,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
let stake_account = rpc_client.get_account(&stake_account_pubkey).unwrap();
|
||||
let stake_account = rpc_client
|
||||
.get_account_with_commitment(&stake_account_pubkey, CommitmentConfig::recent())
|
||||
.unwrap()
|
||||
.value
|
||||
.unwrap();
|
||||
let stake_state: StakeState = stake_account.state().unwrap();
|
||||
let current_authority = match stake_state {
|
||||
StakeState::Initialized(meta) => meta.authorized.staker,
|
||||
@@ -843,8 +853,7 @@ fn test_stake_authorize_with_fee_payer() {
|
||||
run_local_faucet(alice, sender, None);
|
||||
let faucet_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_socket_with_commitment(leader_data.rpc, CommitmentConfig::recent());
|
||||
let rpc_client = RpcClient::new_socket(leader_data.rpc);
|
||||
let default_signer = Keypair::new();
|
||||
let default_pubkey = default_signer.pubkey();
|
||||
|
||||
@@ -914,7 +923,6 @@ fn test_stake_authorize_with_fee_payer() {
|
||||
nonce_account: None,
|
||||
nonce_authority: 0,
|
||||
fee_payer: 1,
|
||||
custodian: None,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
// `config` balance has not changed, despite submitting the TX
|
||||
@@ -924,7 +932,10 @@ fn test_stake_authorize_with_fee_payer() {
|
||||
check_recent_balance(100_000 - SIG_FEE - SIG_FEE, &rpc_client, &payer_pubkey);
|
||||
|
||||
// Assign authority with offline fee payer
|
||||
let (blockhash, _) = rpc_client.get_recent_blockhash().unwrap();
|
||||
let (blockhash, _, _) = rpc_client
|
||||
.get_recent_blockhash_with_commitment(CommitmentConfig::recent())
|
||||
.unwrap()
|
||||
.value;
|
||||
config_offline.command = CliCommand::StakeAuthorize {
|
||||
stake_account_pubkey,
|
||||
new_authorizations: vec![(StakeAuthorize::Staker, payer_pubkey, 0)],
|
||||
@@ -933,7 +944,6 @@ fn test_stake_authorize_with_fee_payer() {
|
||||
nonce_account: None,
|
||||
nonce_authority: 0,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
};
|
||||
config_offline.output_format = OutputFormat::JsonCompact;
|
||||
let sign_reply = process_command(&config_offline).unwrap();
|
||||
@@ -949,7 +959,6 @@ fn test_stake_authorize_with_fee_payer() {
|
||||
nonce_account: None,
|
||||
nonce_authority: 0,
|
||||
fee_payer: 0,
|
||||
custodian: None,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
// `config`'s balance again has not changed
|
||||
@@ -977,8 +986,7 @@ fn test_stake_split() {
|
||||
run_local_faucet(alice, sender, None);
|
||||
let faucet_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_socket_with_commitment(leader_data.rpc, CommitmentConfig::recent());
|
||||
let rpc_client = RpcClient::new_socket(leader_data.rpc);
|
||||
let default_signer = Keypair::new();
|
||||
let offline_signer = Keypair::new();
|
||||
|
||||
@@ -1129,8 +1137,7 @@ fn test_stake_set_lockup() {
|
||||
run_local_faucet(alice, sender, None);
|
||||
let faucet_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_socket_with_commitment(leader_data.rpc, CommitmentConfig::recent());
|
||||
let rpc_client = RpcClient::new_socket(leader_data.rpc);
|
||||
let default_signer = Keypair::new();
|
||||
let offline_signer = Keypair::new();
|
||||
|
||||
@@ -1211,7 +1218,11 @@ fn test_stake_set_lockup() {
|
||||
fee_payer: 0,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
let stake_account = rpc_client.get_account(&stake_account_pubkey).unwrap();
|
||||
let stake_account = rpc_client
|
||||
.get_account_with_commitment(&stake_account_pubkey, CommitmentConfig::recent())
|
||||
.unwrap()
|
||||
.value
|
||||
.unwrap();
|
||||
let stake_state: StakeState = stake_account.state().unwrap();
|
||||
let current_lockup = match stake_state {
|
||||
StakeState::Initialized(meta) => meta.lockup,
|
||||
@@ -1262,7 +1273,11 @@ fn test_stake_set_lockup() {
|
||||
fee_payer: 0,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
let stake_account = rpc_client.get_account(&stake_account_pubkey).unwrap();
|
||||
let stake_account = rpc_client
|
||||
.get_account_with_commitment(&stake_account_pubkey, CommitmentConfig::recent())
|
||||
.unwrap()
|
||||
.value
|
||||
.unwrap();
|
||||
let stake_state: StakeState = stake_account.state().unwrap();
|
||||
let current_lockup = match stake_state {
|
||||
StakeState::Initialized(meta) => meta.lockup,
|
||||
@@ -1355,7 +1370,11 @@ fn test_stake_set_lockup() {
|
||||
fee_payer: 0,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
let stake_account = rpc_client.get_account(&stake_account_pubkey).unwrap();
|
||||
let stake_account = rpc_client
|
||||
.get_account_with_commitment(&stake_account_pubkey, CommitmentConfig::recent())
|
||||
.unwrap()
|
||||
.value
|
||||
.unwrap();
|
||||
let stake_state: StakeState = stake_account.state().unwrap();
|
||||
let current_lockup = match stake_state {
|
||||
StakeState::Initialized(meta) => meta.lockup,
|
||||
@@ -1387,8 +1406,7 @@ fn test_offline_nonced_create_stake_account_and_withdraw() {
|
||||
run_local_faucet(alice, sender, None);
|
||||
let faucet_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_socket_with_commitment(leader_data.rpc, CommitmentConfig::recent());
|
||||
let rpc_client = RpcClient::new_socket(leader_data.rpc);
|
||||
|
||||
let mut config = CliConfig::recent_for_tests();
|
||||
let default_signer = keypair_from_seed(&[1u8; 32]).unwrap();
|
||||
|
@@ -34,8 +34,7 @@ fn test_transfer() {
|
||||
run_local_faucet(mint_keypair, sender, None);
|
||||
let faucet_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_socket_with_commitment(leader_data.rpc, CommitmentConfig::recent());
|
||||
let rpc_client = RpcClient::new_socket(leader_data.rpc);
|
||||
|
||||
let default_signer = Keypair::new();
|
||||
let default_offline_signer = Keypair::new();
|
||||
@@ -98,7 +97,10 @@ fn test_transfer() {
|
||||
check_recent_balance(50, &rpc_client, &offline_pubkey);
|
||||
|
||||
// Offline transfer
|
||||
let (blockhash, _) = rpc_client.get_recent_blockhash().unwrap();
|
||||
let (blockhash, _, _) = rpc_client
|
||||
.get_recent_blockhash_with_commitment(CommitmentConfig::recent())
|
||||
.unwrap()
|
||||
.value;
|
||||
offline.command = CliCommand::Transfer {
|
||||
amount: SpendAmount::Some(10),
|
||||
to: recipient_pubkey,
|
||||
@@ -267,8 +269,7 @@ fn test_transfer_multisession_signing() {
|
||||
let config = CliConfig::recent_for_tests();
|
||||
|
||||
// Setup accounts
|
||||
let rpc_client =
|
||||
RpcClient::new_socket_with_commitment(leader_data.rpc, CommitmentConfig::recent());
|
||||
let rpc_client = RpcClient::new_socket(leader_data.rpc);
|
||||
request_and_confirm_airdrop(
|
||||
&rpc_client,
|
||||
&faucet_addr,
|
||||
@@ -291,7 +292,10 @@ fn test_transfer_multisession_signing() {
|
||||
|
||||
check_ready(&rpc_client);
|
||||
|
||||
let (blockhash, _) = rpc_client.get_recent_blockhash().unwrap();
|
||||
let (blockhash, _, _) = rpc_client
|
||||
.get_recent_blockhash_with_commitment(CommitmentConfig::recent())
|
||||
.unwrap()
|
||||
.value;
|
||||
|
||||
// Offline fee-payer signs first
|
||||
let mut fee_payer_config = CliConfig::recent_for_tests();
|
||||
@@ -385,8 +389,7 @@ fn test_transfer_all() {
|
||||
run_local_faucet(mint_keypair, sender, None);
|
||||
let faucet_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_socket_with_commitment(leader_data.rpc, CommitmentConfig::recent());
|
||||
let rpc_client = RpcClient::new_socket(leader_data.rpc);
|
||||
|
||||
let default_signer = Keypair::new();
|
||||
|
||||
|
@@ -30,8 +30,7 @@ fn test_vote_authorize_and_withdraw() {
|
||||
run_local_faucet(alice, sender, None);
|
||||
let faucet_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client =
|
||||
RpcClient::new_socket_with_commitment(leader_data.rpc, CommitmentConfig::recent());
|
||||
let rpc_client = RpcClient::new_socket(leader_data.rpc);
|
||||
let default_signer = Keypair::new();
|
||||
|
||||
let mut config = CliConfig::recent_for_tests();
|
||||
@@ -61,7 +60,9 @@ fn test_vote_authorize_and_withdraw() {
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
let vote_account = rpc_client
|
||||
.get_account(&vote_account_keypair.pubkey())
|
||||
.get_account_with_commitment(&vote_account_keypair.pubkey(), CommitmentConfig::recent())
|
||||
.unwrap()
|
||||
.value
|
||||
.unwrap();
|
||||
let vote_state: VoteStateVersions = vote_account.state().unwrap();
|
||||
let authorized_withdrawer = vote_state.convert_to_current().authorized_withdrawer;
|
||||
@@ -99,7 +100,9 @@ fn test_vote_authorize_and_withdraw() {
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
let vote_account = rpc_client
|
||||
.get_account(&vote_account_keypair.pubkey())
|
||||
.get_account_with_commitment(&vote_account_keypair.pubkey(), CommitmentConfig::recent())
|
||||
.unwrap()
|
||||
.value
|
||||
.unwrap();
|
||||
let vote_state: VoteStateVersions = vote_account.state().unwrap();
|
||||
let authorized_withdrawer = vote_state.convert_to_current().authorized_withdrawer;
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-client"
|
||||
version = "1.4.26"
|
||||
version = "1.3.24"
|
||||
description = "Solana Client"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -18,18 +18,18 @@ jsonrpc-core = "15.0.0"
|
||||
log = "0.4.8"
|
||||
net2 = "0.2.37"
|
||||
rayon = "1.4.0"
|
||||
reqwest = { version = "0.10.8", default-features = false, features = ["blocking", "rustls-tls", "json"] }
|
||||
reqwest = { version = "0.10.6", default-features = false, features = ["blocking", "rustls-tls", "json"] }
|
||||
semver = "0.11.0"
|
||||
serde = "1.0.112"
|
||||
serde_derive = "1.0.103"
|
||||
serde_json = "1.0.56"
|
||||
solana-account-decoder = { path = "../account-decoder", version = "1.4.26" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.4.26" }
|
||||
solana-net-utils = { path = "../net-utils", version = "1.4.26" }
|
||||
solana-sdk = { path = "../sdk", version = "1.4.26" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "1.4.26" }
|
||||
solana-version = { path = "../version", version = "1.4.26" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "1.4.26" }
|
||||
solana-account-decoder = { path = "../account-decoder", version = "1.3.24" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.3.24" }
|
||||
solana-net-utils = { path = "../net-utils", version = "1.3.24" }
|
||||
solana-sdk = { path = "../sdk", version = "1.3.24" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "1.3.24" }
|
||||
solana-version = { path = "../version", version = "1.3.24" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "1.3.24" }
|
||||
thiserror = "1.0"
|
||||
tungstenite = "0.10.1"
|
||||
url = "2.1.1"
|
||||
@@ -38,7 +38,7 @@ url = "2.1.1"
|
||||
assert_matches = "1.3.0"
|
||||
jsonrpc-core = "15.0.0"
|
||||
jsonrpc-http-server = "15.0.0"
|
||||
solana-logger = { path = "../logger", version = "1.4.26" }
|
||||
solana-logger = { path = "../logger", version = "1.3.24" }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
@@ -179,7 +179,7 @@ mod tests {
|
||||
fn test_blockhash_query_new_from_matches_ok() {
|
||||
let test_commands = App::new("blockhash_query_test")
|
||||
.nonce_args(false)
|
||||
.offline_args();
|
||||
.offline_args(false);
|
||||
let blockhash = hash(&[1u8]);
|
||||
let blockhash_string = blockhash.to_string();
|
||||
|
||||
|
@@ -5,8 +5,6 @@ use solana_sdk::{
|
||||
use std::io;
|
||||
use thiserror::Error;
|
||||
|
||||
pub use reqwest; // export `reqwest` for clients
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum ClientErrorKind {
|
||||
#[error(transparent)]
|
||||
|
@@ -1,8 +1,6 @@
|
||||
use crate::{
|
||||
client_error::Result,
|
||||
rpc_custom_error,
|
||||
rpc_request::{RpcError, RpcRequest, RpcResponseErrorData},
|
||||
rpc_response::RpcSimulateTransactionResult,
|
||||
rpc_request::{RpcError, RpcRequest},
|
||||
rpc_sender::RpcSender,
|
||||
};
|
||||
use log::*;
|
||||
@@ -33,7 +31,7 @@ impl HttpSender {
|
||||
struct RpcErrorObject {
|
||||
code: i64,
|
||||
message: String,
|
||||
data: serde_json::Value,
|
||||
/*data field omitted*/
|
||||
}
|
||||
|
||||
impl RpcSender for HttpSender {
|
||||
@@ -74,27 +72,11 @@ impl RpcSender for HttpSender {
|
||||
if json["error"].is_object() {
|
||||
return match serde_json::from_value::<RpcErrorObject>(json["error"].clone())
|
||||
{
|
||||
Ok(rpc_error_object) => {
|
||||
let data = match rpc_error_object.code {
|
||||
rpc_custom_error::JSON_RPC_SERVER_ERROR_SEND_TRANSACTION_PREFLIGHT_FAILURE => {
|
||||
match serde_json::from_value::<RpcSimulateTransactionResult>(json["error"]["data"].clone()) {
|
||||
Ok(data) => RpcResponseErrorData::SendTransactionPreflightFailure(data),
|
||||
Err(err) => {
|
||||
debug!("Failed to deserialize RpcSimulateTransactionResult: {:?}", err);
|
||||
RpcResponseErrorData::Empty
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => RpcResponseErrorData::Empty
|
||||
};
|
||||
|
||||
Err(RpcError::RpcResponseError {
|
||||
code: rpc_error_object.code,
|
||||
message: rpc_error_object.message,
|
||||
data,
|
||||
}
|
||||
.into())
|
||||
Ok(rpc_error_object) => Err(RpcError::RpcResponseError {
|
||||
code: rpc_error_object.code,
|
||||
message: rpc_error_object.message,
|
||||
}
|
||||
.into()),
|
||||
Err(err) => Err(RpcError::RpcRequestError(format!(
|
||||
"Failed to deserialize RPC error response: {} [{}]",
|
||||
serde_json::to_string(&json["error"]).unwrap(),
|
||||
|
@@ -12,7 +12,7 @@ use solana_sdk::{
|
||||
signature::Signature,
|
||||
transaction::{self, Transaction, TransactionError},
|
||||
};
|
||||
use solana_transaction_status::{TransactionConfirmationStatus, TransactionStatus};
|
||||
use solana_transaction_status::TransactionStatus;
|
||||
use solana_version::Version;
|
||||
use std::{collections::HashMap, sync::RwLock};
|
||||
|
||||
@@ -48,10 +48,6 @@ impl RpcSender for MockSender {
|
||||
return Ok(Value::Null);
|
||||
}
|
||||
let val = match request {
|
||||
RpcRequest::GetAccountInfo => serde_json::to_value(Response {
|
||||
context: RpcResponseContext { slot: 1 },
|
||||
value: Value::Null,
|
||||
})?,
|
||||
RpcRequest::GetBalance => serde_json::to_value(Response {
|
||||
context: RpcResponseContext { slot: 1 },
|
||||
value: Value::Number(Number::from(50)),
|
||||
@@ -69,7 +65,6 @@ impl RpcSender for MockSender {
|
||||
slots_in_epoch: 32,
|
||||
absolute_slot: 34,
|
||||
block_height: 34,
|
||||
transaction_count: Some(123),
|
||||
})?,
|
||||
RpcRequest::GetFeeCalculatorForBlockhash => {
|
||||
let value = if self.url == "blockhash_expired" {
|
||||
@@ -106,7 +101,6 @@ impl RpcSender for MockSender {
|
||||
slot: 1,
|
||||
confirmations: None,
|
||||
err,
|
||||
confirmation_status: Some(TransactionConfirmationStatus::Finalized),
|
||||
})
|
||||
};
|
||||
let statuses: Vec<Option<TransactionStatus>> = params.as_array().unwrap()[0]
|
||||
|
@@ -1,7 +1,4 @@
|
||||
use crate::{
|
||||
rpc_config::{RpcSignatureSubscribeConfig, RpcTransactionLogsConfig, RpcTransactionLogsFilter},
|
||||
rpc_response::{Response as RpcResponse, RpcLogsResponse, RpcSignatureResult, SlotInfo},
|
||||
};
|
||||
use crate::rpc_response::{Response as RpcResponse, RpcSignatureResult, SlotInfo};
|
||||
use log::*;
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde_json::{
|
||||
@@ -23,6 +20,8 @@ use thiserror::Error;
|
||||
use tungstenite::{client::AutoStream, connect, Message, WebSocket};
|
||||
use url::{ParseError, Url};
|
||||
|
||||
type PubsubSignatureResponse = PubsubClientSubscription<RpcResponse<RpcSignatureResult>>;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum PubsubClientError {
|
||||
#[error("url parse error")]
|
||||
@@ -34,8 +33,8 @@ pub enum PubsubClientError {
|
||||
#[error("json parse error")]
|
||||
JsonParseError(#[from] serde_json::error::Error),
|
||||
|
||||
#[error("unexpected message format: {0}")]
|
||||
UnexpectedMessageError(String),
|
||||
#[error("unexpected message format")]
|
||||
UnexpectedMessageError,
|
||||
}
|
||||
|
||||
pub struct PubsubClientSubscription<T>
|
||||
@@ -90,11 +89,8 @@ where
|
||||
return Ok(x);
|
||||
}
|
||||
}
|
||||
// TODO: Add proper JSON RPC response/error handling...
|
||||
Err(PubsubClientError::UnexpectedMessageError(format!(
|
||||
"{:?}",
|
||||
json_msg
|
||||
)))
|
||||
|
||||
Err(PubsubClientError::UnexpectedMessageError)
|
||||
}
|
||||
|
||||
pub fn send_unsubscribe(&self) -> Result<(), PubsubClientError> {
|
||||
@@ -118,18 +114,14 @@ where
|
||||
let message_text = &message.into_text().unwrap();
|
||||
let json_msg: Map<String, Value> = serde_json::from_str(message_text)?;
|
||||
|
||||
if let Some(Object(params)) = json_msg.get("params") {
|
||||
if let Some(result) = params.get("result") {
|
||||
let x: T = serde_json::from_value::<T>(result.clone()).unwrap();
|
||||
if let Some(Object(value_1)) = json_msg.get("params") {
|
||||
if let Some(value_2) = value_1.get("result") {
|
||||
let x: T = serde_json::from_value::<T>(value_2.clone()).unwrap();
|
||||
return Ok(x);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Add proper JSON RPC response/error handling...
|
||||
Err(PubsubClientError::UnexpectedMessageError(format!(
|
||||
"{:?}",
|
||||
json_msg
|
||||
)))
|
||||
Err(PubsubClientError::UnexpectedMessageError)
|
||||
}
|
||||
|
||||
pub fn shutdown(&mut self) -> std::thread::Result<()> {
|
||||
@@ -146,79 +138,15 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub type LogsSubscription = (
|
||||
PubsubClientSubscription<RpcResponse<RpcLogsResponse>>,
|
||||
Receiver<RpcResponse<RpcLogsResponse>>,
|
||||
);
|
||||
pub type SlotsSubscription = (PubsubClientSubscription<SlotInfo>, Receiver<SlotInfo>);
|
||||
pub type SignatureSubscription = (
|
||||
PubsubClientSubscription<RpcResponse<RpcSignatureResult>>,
|
||||
Receiver<RpcResponse<RpcSignatureResult>>,
|
||||
);
|
||||
const SLOT_OPERATION: &str = "slot";
|
||||
const SIGNATURE_OPERATION: &str = "signature";
|
||||
|
||||
pub struct PubsubClient {}
|
||||
|
||||
impl PubsubClient {
|
||||
pub fn logs_subscribe(
|
||||
pub fn slot_subscribe(
|
||||
url: &str,
|
||||
filter: RpcTransactionLogsFilter,
|
||||
config: RpcTransactionLogsConfig,
|
||||
) -> Result<LogsSubscription, PubsubClientError> {
|
||||
let url = Url::parse(url)?;
|
||||
let (socket, _response) = connect(url)?;
|
||||
let (sender, receiver) = channel();
|
||||
|
||||
let socket = Arc::new(RwLock::new(socket));
|
||||
let socket_clone = socket.clone();
|
||||
let exit = Arc::new(AtomicBool::new(false));
|
||||
let exit_clone = exit.clone();
|
||||
|
||||
let subscription_id =
|
||||
PubsubClientSubscription::<RpcResponse<RpcLogsResponse>>::send_subscribe(
|
||||
&socket_clone,
|
||||
json!({
|
||||
"jsonrpc":"2.0","id":1,"method":"logsSubscribe","params":[filter, config]
|
||||
})
|
||||
.to_string(),
|
||||
)?;
|
||||
|
||||
let t_cleanup = std::thread::spawn(move || {
|
||||
loop {
|
||||
if exit_clone.load(Ordering::Relaxed) {
|
||||
break;
|
||||
}
|
||||
|
||||
match PubsubClientSubscription::read_message(&socket_clone) {
|
||||
Ok(message) => match sender.send(message) {
|
||||
Ok(_) => (),
|
||||
Err(err) => {
|
||||
info!("receive error: {:?}", err);
|
||||
break;
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
info!("receive error: {:?}", err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
info!("websocket - exited receive loop");
|
||||
});
|
||||
|
||||
let result = PubsubClientSubscription {
|
||||
message_type: PhantomData,
|
||||
operation: "logs",
|
||||
socket,
|
||||
subscription_id,
|
||||
t_cleanup: Some(t_cleanup),
|
||||
exit,
|
||||
};
|
||||
|
||||
Ok((result, receiver))
|
||||
}
|
||||
|
||||
pub fn slot_subscribe(url: &str) -> Result<SlotsSubscription, PubsubClientError> {
|
||||
) -> Result<(PubsubClientSubscription<SlotInfo>, Receiver<SlotInfo>), PubsubClientError> {
|
||||
let url = Url::parse(url)?;
|
||||
let (socket, _response) = connect(url)?;
|
||||
let (sender, receiver) = channel::<SlotInfo>();
|
||||
@@ -230,37 +158,41 @@ impl PubsubClient {
|
||||
let subscription_id = PubsubClientSubscription::<SlotInfo>::send_subscribe(
|
||||
&socket_clone,
|
||||
json!({
|
||||
"jsonrpc":"2.0","id":1,"method":"slotSubscribe","params":[]
|
||||
"jsonrpc":"2.0","id":1,"method":format!("{}Subscribe", SLOT_OPERATION),"params":[]
|
||||
})
|
||||
.to_string(),
|
||||
)?;
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let t_cleanup = std::thread::spawn(move || {
|
||||
loop {
|
||||
if exit_clone.load(Ordering::Relaxed) {
|
||||
break;
|
||||
}
|
||||
match PubsubClientSubscription::read_message(&socket_clone) {
|
||||
Ok(message) => match sender.send(message) {
|
||||
|
||||
let message: Result<SlotInfo, PubsubClientError> =
|
||||
PubsubClientSubscription::read_message(&socket_clone);
|
||||
|
||||
if let Ok(msg) = message {
|
||||
match sender.send(msg) {
|
||||
Ok(_) => (),
|
||||
Err(err) => {
|
||||
info!("receive error: {:?}", err);
|
||||
break;
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
info!("receive error: {:?}", err);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
info!("receive error: {:?}", message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
info!("websocket - exited receive loop");
|
||||
});
|
||||
|
||||
let result = PubsubClientSubscription {
|
||||
let result: PubsubClientSubscription<SlotInfo> = PubsubClientSubscription {
|
||||
message_type: PhantomData,
|
||||
operation: "slot",
|
||||
operation: SLOT_OPERATION,
|
||||
socket,
|
||||
subscription_id,
|
||||
t_cleanup: Some(t_cleanup),
|
||||
@@ -273,11 +205,16 @@ impl PubsubClient {
|
||||
pub fn signature_subscribe(
|
||||
url: &str,
|
||||
signature: &Signature,
|
||||
config: Option<RpcSignatureSubscribeConfig>,
|
||||
) -> Result<SignatureSubscription, PubsubClientError> {
|
||||
) -> Result<
|
||||
(
|
||||
PubsubSignatureResponse,
|
||||
Receiver<RpcResponse<RpcSignatureResult>>,
|
||||
),
|
||||
PubsubClientError,
|
||||
> {
|
||||
let url = Url::parse(url)?;
|
||||
let (socket, _response) = connect(url)?;
|
||||
let (sender, receiver) = channel();
|
||||
let (sender, receiver) = channel::<RpcResponse<RpcSignatureResult>>();
|
||||
|
||||
let socket = Arc::new(RwLock::new(socket));
|
||||
let socket_clone = socket.clone();
|
||||
@@ -286,10 +223,10 @@ impl PubsubClient {
|
||||
let body = json!({
|
||||
"jsonrpc":"2.0",
|
||||
"id":1,
|
||||
"method":"signatureSubscribe",
|
||||
"method":format!("{}Subscribe", SIGNATURE_OPERATION),
|
||||
"params":[
|
||||
signature.to_string(),
|
||||
config
|
||||
{"enableReceivedNotification": true }
|
||||
]
|
||||
})
|
||||
.to_string();
|
||||
@@ -297,7 +234,8 @@ impl PubsubClient {
|
||||
PubsubClientSubscription::<RpcResponse<RpcSignatureResult>>::send_subscribe(
|
||||
&socket_clone,
|
||||
body,
|
||||
)?;
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let t_cleanup = std::thread::spawn(move || {
|
||||
loop {
|
||||
@@ -325,14 +263,15 @@ impl PubsubClient {
|
||||
info!("websocket - exited receive loop");
|
||||
});
|
||||
|
||||
let result = PubsubClientSubscription {
|
||||
message_type: PhantomData,
|
||||
operation: "signature",
|
||||
socket,
|
||||
subscription_id,
|
||||
t_cleanup: Some(t_cleanup),
|
||||
exit,
|
||||
};
|
||||
let result: PubsubClientSubscription<RpcResponse<RpcSignatureResult>> =
|
||||
PubsubClientSubscription {
|
||||
message_type: PhantomData,
|
||||
operation: SIGNATURE_OPERATION,
|
||||
socket,
|
||||
subscription_id,
|
||||
t_cleanup: Some(t_cleanup),
|
||||
exit,
|
||||
};
|
||||
|
||||
Ok((result, receiver))
|
||||
}
|
||||
|
@@ -8,7 +8,7 @@ use crate::{
|
||||
RpcProgramAccountsConfig, RpcSendTransactionConfig, RpcSimulateTransactionConfig,
|
||||
RpcTokenAccountsFilter,
|
||||
},
|
||||
rpc_request::{RpcError, RpcRequest, RpcResponseErrorData, TokenAccountsFilter},
|
||||
rpc_request::{RpcError, RpcRequest, TokenAccountsFilter},
|
||||
rpc_response::*,
|
||||
rpc_sender::RpcSender,
|
||||
};
|
||||
@@ -40,7 +40,6 @@ use solana_transaction_status::{
|
||||
};
|
||||
use solana_vote_program::vote_state::MAX_LOCKOUT_HISTORY;
|
||||
use std::{
|
||||
cmp::min,
|
||||
net::SocketAddr,
|
||||
sync::RwLock,
|
||||
thread::sleep,
|
||||
@@ -49,7 +48,6 @@ use std::{
|
||||
|
||||
pub struct RpcClient {
|
||||
sender: Box<dyn RpcSender + Send + Sync + 'static>,
|
||||
commitment_config: CommitmentConfig,
|
||||
default_cluster_transaction_encoding: RwLock<Option<UiTransactionEncoding>>,
|
||||
}
|
||||
|
||||
@@ -74,65 +72,33 @@ fn serialize_encode_transaction(
|
||||
}
|
||||
|
||||
impl RpcClient {
|
||||
fn new_sender<T: RpcSender + Send + Sync + 'static>(
|
||||
sender: T,
|
||||
commitment_config: CommitmentConfig,
|
||||
) -> Self {
|
||||
pub fn new_sender<T: RpcSender + Send + Sync + 'static>(sender: T) -> Self {
|
||||
Self {
|
||||
sender: Box::new(sender),
|
||||
default_cluster_transaction_encoding: RwLock::new(None),
|
||||
commitment_config,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(url: String) -> Self {
|
||||
Self::new_with_commitment(url, CommitmentConfig::default())
|
||||
}
|
||||
|
||||
pub fn new_with_commitment(url: String, commitment_config: CommitmentConfig) -> Self {
|
||||
Self::new_sender(HttpSender::new(url), commitment_config)
|
||||
Self::new_sender(HttpSender::new(url))
|
||||
}
|
||||
|
||||
pub fn new_with_timeout(url: String, timeout: Duration) -> Self {
|
||||
Self::new_sender(
|
||||
HttpSender::new_with_timeout(url, timeout),
|
||||
CommitmentConfig::default(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn new_with_timeout_and_commitment(
|
||||
url: String,
|
||||
timeout: Duration,
|
||||
commitment_config: CommitmentConfig,
|
||||
) -> Self {
|
||||
Self::new_sender(
|
||||
HttpSender::new_with_timeout(url, timeout),
|
||||
commitment_config,
|
||||
)
|
||||
Self::new_sender(HttpSender::new_with_timeout(url, timeout))
|
||||
}
|
||||
|
||||
pub fn new_mock(url: String) -> Self {
|
||||
Self::new_sender(MockSender::new(url), CommitmentConfig::default())
|
||||
Self::new_sender(MockSender::new(url))
|
||||
}
|
||||
|
||||
pub fn new_mock_with_mocks(url: String, mocks: Mocks) -> Self {
|
||||
Self::new_sender(
|
||||
MockSender::new_with_mocks(url, mocks),
|
||||
CommitmentConfig::default(),
|
||||
)
|
||||
Self::new_sender(MockSender::new_with_mocks(url, mocks))
|
||||
}
|
||||
|
||||
pub fn new_socket(addr: SocketAddr) -> Self {
|
||||
Self::new(get_rpc_request_str(addr, false))
|
||||
}
|
||||
|
||||
pub fn new_socket_with_commitment(
|
||||
addr: SocketAddr,
|
||||
commitment_config: CommitmentConfig,
|
||||
) -> Self {
|
||||
Self::new_with_commitment(get_rpc_request_str(addr, false), commitment_config)
|
||||
}
|
||||
|
||||
pub fn new_socket_with_timeout(addr: SocketAddr, timeout: Duration) -> Self {
|
||||
let url = get_rpc_request_str(addr, false);
|
||||
Self::new_with_timeout(url, timeout)
|
||||
@@ -140,14 +106,10 @@ impl RpcClient {
|
||||
|
||||
pub fn confirm_transaction(&self, signature: &Signature) -> ClientResult<bool> {
|
||||
Ok(self
|
||||
.confirm_transaction_with_commitment(signature, self.commitment_config)?
|
||||
.confirm_transaction_with_commitment(signature, CommitmentConfig::default())?
|
||||
.value)
|
||||
}
|
||||
|
||||
pub fn commitment(&self) -> CommitmentConfig {
|
||||
self.commitment_config
|
||||
}
|
||||
|
||||
pub fn confirm_transaction_with_commitment(
|
||||
&self,
|
||||
signature: &Signature,
|
||||
@@ -166,13 +128,7 @@ impl RpcClient {
|
||||
}
|
||||
|
||||
pub fn send_transaction(&self, transaction: &Transaction) -> ClientResult<Signature> {
|
||||
self.send_transaction_with_config(
|
||||
transaction,
|
||||
RpcSendTransactionConfig {
|
||||
preflight_commitment: Some(self.commitment_config.commitment),
|
||||
..RpcSendTransactionConfig::default()
|
||||
},
|
||||
)
|
||||
self.send_transaction_with_config(transaction, RpcSendTransactionConfig::default())
|
||||
}
|
||||
|
||||
fn default_cluster_transaction_encoding(&self) -> Result<UiTransactionEncoding, RpcError> {
|
||||
@@ -215,33 +171,10 @@ impl RpcClient {
|
||||
..config
|
||||
};
|
||||
let serialized_encoded = serialize_encode_transaction(transaction, encoding)?;
|
||||
let signature_base58_str: String = match self.send(
|
||||
let signature_base58_str: String = self.send(
|
||||
RpcRequest::SendTransaction,
|
||||
json!([serialized_encoded, config]),
|
||||
) {
|
||||
Ok(signature_base58_str) => signature_base58_str,
|
||||
Err(err) => {
|
||||
if let ClientErrorKind::RpcError(RpcError::RpcResponseError {
|
||||
code,
|
||||
message,
|
||||
data,
|
||||
}) = &err.kind
|
||||
{
|
||||
debug!("{} {}", code, message);
|
||||
if let RpcResponseErrorData::SendTransactionPreflightFailure(
|
||||
RpcSimulateTransactionResult {
|
||||
logs: Some(logs), ..
|
||||
},
|
||||
) = data
|
||||
{
|
||||
for (i, log) in logs.iter().enumerate() {
|
||||
debug!("{:>3}: {}", i + 1, log);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Err(err);
|
||||
}
|
||||
};
|
||||
)?;
|
||||
|
||||
let signature = signature_base58_str
|
||||
.parse::<Signature>()
|
||||
@@ -265,13 +198,7 @@ impl RpcClient {
|
||||
&self,
|
||||
transaction: &Transaction,
|
||||
) -> RpcResult<RpcSimulateTransactionResult> {
|
||||
self.simulate_transaction_with_config(
|
||||
transaction,
|
||||
RpcSimulateTransactionConfig {
|
||||
commitment: Some(self.commitment_config),
|
||||
..RpcSimulateTransactionConfig::default()
|
||||
},
|
||||
)
|
||||
self.simulate_transaction_with_config(transaction, RpcSimulateTransactionConfig::default())
|
||||
}
|
||||
|
||||
pub fn simulate_transaction_with_config(
|
||||
@@ -299,7 +226,7 @@ impl RpcClient {
|
||||
&self,
|
||||
signature: &Signature,
|
||||
) -> ClientResult<Option<transaction::Result<()>>> {
|
||||
self.get_signature_status_with_commitment(signature, self.commitment_config)
|
||||
self.get_signature_status_with_commitment(signature, CommitmentConfig::default())
|
||||
}
|
||||
|
||||
pub fn get_signature_statuses(
|
||||
@@ -357,7 +284,7 @@ impl RpcClient {
|
||||
}
|
||||
|
||||
pub fn get_slot(&self) -> ClientResult<Slot> {
|
||||
self.get_slot_with_commitment(self.commitment_config)
|
||||
self.get_slot_with_commitment(CommitmentConfig::default())
|
||||
}
|
||||
|
||||
pub fn get_slot_with_commitment(
|
||||
@@ -367,10 +294,6 @@ impl RpcClient {
|
||||
self.send(RpcRequest::GetSlot, json!([commitment_config]))
|
||||
}
|
||||
|
||||
pub fn supply(&self) -> RpcResult<RpcSupply> {
|
||||
self.supply_with_commitment(self.commitment_config)
|
||||
}
|
||||
|
||||
pub fn supply_with_commitment(
|
||||
&self,
|
||||
commitment_config: CommitmentConfig,
|
||||
@@ -379,7 +302,7 @@ impl RpcClient {
|
||||
}
|
||||
|
||||
pub fn total_supply(&self) -> ClientResult<u64> {
|
||||
self.total_supply_with_commitment(self.commitment_config)
|
||||
self.total_supply_with_commitment(CommitmentConfig::default())
|
||||
}
|
||||
|
||||
pub fn total_supply_with_commitment(
|
||||
@@ -397,7 +320,7 @@ impl RpcClient {
|
||||
}
|
||||
|
||||
pub fn get_vote_accounts(&self) -> ClientResult<RpcVoteAccountStatus> {
|
||||
self.get_vote_accounts_with_commitment(self.commitment_config)
|
||||
self.get_vote_accounts_with_commitment(CommitmentConfig::default())
|
||||
}
|
||||
|
||||
pub fn get_vote_accounts_with_commitment(
|
||||
@@ -407,38 +330,6 @@ impl RpcClient {
|
||||
self.send(RpcRequest::GetVoteAccounts, json!([commitment_config]))
|
||||
}
|
||||
|
||||
pub fn wait_for_max_stake(
|
||||
&self,
|
||||
commitment: CommitmentConfig,
|
||||
max_stake_percent: f32,
|
||||
) -> ClientResult<()> {
|
||||
let mut current_percent;
|
||||
loop {
|
||||
let vote_accounts = self.get_vote_accounts_with_commitment(commitment)?;
|
||||
|
||||
let mut max = 0;
|
||||
let total_active_stake = vote_accounts
|
||||
.current
|
||||
.iter()
|
||||
.chain(vote_accounts.delinquent.iter())
|
||||
.map(|vote_account| {
|
||||
max = std::cmp::max(max, vote_account.activated_stake);
|
||||
vote_account.activated_stake
|
||||
})
|
||||
.sum::<u64>();
|
||||
current_percent = 100f32 * max as f32 / total_active_stake as f32;
|
||||
if current_percent < max_stake_percent {
|
||||
break;
|
||||
}
|
||||
info!(
|
||||
"Waiting for stake to drop below {} current: {:.1}",
|
||||
max_stake_percent, current_percent
|
||||
);
|
||||
sleep(Duration::from_secs(10));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_cluster_nodes(&self) -> ClientResult<Vec<RpcContactInfo>> {
|
||||
self.send(RpcRequest::GetClusterNodes, Value::Null)
|
||||
}
|
||||
@@ -557,7 +448,7 @@ impl RpcClient {
|
||||
}
|
||||
|
||||
pub fn get_epoch_info(&self) -> ClientResult<EpochInfo> {
|
||||
self.get_epoch_info_with_commitment(self.commitment_config)
|
||||
self.get_epoch_info_with_commitment(CommitmentConfig::default())
|
||||
}
|
||||
|
||||
pub fn get_epoch_info_with_commitment(
|
||||
@@ -571,7 +462,7 @@ impl RpcClient {
|
||||
&self,
|
||||
slot: Option<Slot>,
|
||||
) -> ClientResult<Option<RpcLeaderSchedule>> {
|
||||
self.get_leader_schedule_with_commitment(slot, self.commitment_config)
|
||||
self.get_leader_schedule_with_commitment(slot, CommitmentConfig::default())
|
||||
}
|
||||
|
||||
pub fn get_leader_schedule_with_commitment(
|
||||
@@ -665,10 +556,8 @@ impl RpcClient {
|
||||
}
|
||||
}
|
||||
|
||||
/// Note that `get_account` returns `Err(..)` if the account does not exist whereas
|
||||
/// `get_account_with_commitment` returns `Ok(None)` if the account does not exist.
|
||||
pub fn get_account(&self, pubkey: &Pubkey) -> ClientResult<Account> {
|
||||
self.get_account_with_commitment(pubkey, self.commitment_config)?
|
||||
self.get_account_with_commitment(pubkey, CommitmentConfig::default())?
|
||||
.value
|
||||
.ok_or_else(|| RpcError::ForUser(format!("AccountNotFound: pubkey={}", pubkey)).into())
|
||||
}
|
||||
@@ -716,7 +605,7 @@ impl RpcClient {
|
||||
|
||||
pub fn get_multiple_accounts(&self, pubkeys: &[Pubkey]) -> ClientResult<Vec<Option<Account>>> {
|
||||
Ok(self
|
||||
.get_multiple_accounts_with_commitment(pubkeys, self.commitment_config)?
|
||||
.get_multiple_accounts_with_commitment(pubkeys, CommitmentConfig::default())?
|
||||
.value)
|
||||
}
|
||||
|
||||
@@ -770,7 +659,7 @@ impl RpcClient {
|
||||
/// Request the balance of the account `pubkey`.
|
||||
pub fn get_balance(&self, pubkey: &Pubkey) -> ClientResult<u64> {
|
||||
Ok(self
|
||||
.get_balance_with_commitment(pubkey, self.commitment_config)?
|
||||
.get_balance_with_commitment(pubkey, CommitmentConfig::default())?
|
||||
.value)
|
||||
}
|
||||
|
||||
@@ -792,7 +681,6 @@ impl RpcClient {
|
||||
filters: None,
|
||||
account_config: RpcAccountInfoConfig {
|
||||
encoding: Some(UiAccountEncoding::Base64),
|
||||
commitment: Some(self.commitment_config),
|
||||
..RpcAccountInfoConfig::default()
|
||||
},
|
||||
},
|
||||
@@ -813,7 +701,7 @@ impl RpcClient {
|
||||
|
||||
/// Request the transaction count.
|
||||
pub fn get_transaction_count(&self) -> ClientResult<u64> {
|
||||
self.get_transaction_count_with_commitment(self.commitment_config)
|
||||
self.get_transaction_count_with_commitment(CommitmentConfig::default())
|
||||
}
|
||||
|
||||
pub fn get_transaction_count_with_commitment(
|
||||
@@ -825,7 +713,7 @@ impl RpcClient {
|
||||
|
||||
pub fn get_recent_blockhash(&self) -> ClientResult<(Hash, FeeCalculator)> {
|
||||
let (blockhash, fee_calculator, _last_valid_slot) = self
|
||||
.get_recent_blockhash_with_commitment(self.commitment_config)?
|
||||
.get_recent_blockhash_with_commitment(CommitmentConfig::default())?
|
||||
.value;
|
||||
Ok((blockhash, fee_calculator))
|
||||
}
|
||||
@@ -882,7 +770,10 @@ impl RpcClient {
|
||||
blockhash: &Hash,
|
||||
) -> ClientResult<Option<FeeCalculator>> {
|
||||
Ok(self
|
||||
.get_fee_calculator_for_blockhash_with_commitment(blockhash, self.commitment_config)?
|
||||
.get_fee_calculator_for_blockhash_with_commitment(
|
||||
blockhash,
|
||||
CommitmentConfig::default(),
|
||||
)?
|
||||
.value)
|
||||
}
|
||||
|
||||
@@ -958,7 +849,7 @@ impl RpcClient {
|
||||
|
||||
pub fn get_token_account(&self, pubkey: &Pubkey) -> ClientResult<Option<UiTokenAccount>> {
|
||||
Ok(self
|
||||
.get_token_account_with_commitment(pubkey, self.commitment_config)?
|
||||
.get_token_account_with_commitment(pubkey, CommitmentConfig::default())?
|
||||
.value)
|
||||
}
|
||||
|
||||
@@ -1019,7 +910,7 @@ impl RpcClient {
|
||||
|
||||
pub fn get_token_account_balance(&self, pubkey: &Pubkey) -> ClientResult<UiTokenAmount> {
|
||||
Ok(self
|
||||
.get_token_account_balance_with_commitment(pubkey, self.commitment_config)?
|
||||
.get_token_account_balance_with_commitment(pubkey, CommitmentConfig::default())?
|
||||
.value)
|
||||
}
|
||||
|
||||
@@ -1043,7 +934,7 @@ impl RpcClient {
|
||||
.get_token_accounts_by_delegate_with_commitment(
|
||||
delegate,
|
||||
token_account_filter,
|
||||
self.commitment_config,
|
||||
CommitmentConfig::default(),
|
||||
)?
|
||||
.value)
|
||||
}
|
||||
@@ -1082,7 +973,7 @@ impl RpcClient {
|
||||
.get_token_accounts_by_owner_with_commitment(
|
||||
owner,
|
||||
token_account_filter,
|
||||
self.commitment_config,
|
||||
CommitmentConfig::default(),
|
||||
)?
|
||||
.value)
|
||||
}
|
||||
@@ -1114,7 +1005,7 @@ impl RpcClient {
|
||||
|
||||
pub fn get_token_supply(&self, mint: &Pubkey) -> ClientResult<UiTokenAmount> {
|
||||
Ok(self
|
||||
.get_token_supply_with_commitment(mint, self.commitment_config)?
|
||||
.get_token_supply_with_commitment(mint, CommitmentConfig::default())?
|
||||
.value)
|
||||
}
|
||||
|
||||
@@ -1195,7 +1086,7 @@ impl RpcClient {
|
||||
|
||||
/// Poll the server to confirm a transaction.
|
||||
pub fn poll_for_signature(&self, signature: &Signature) -> ClientResult<()> {
|
||||
self.poll_for_signature_with_commitment(signature, self.commitment_config)
|
||||
self.poll_for_signature_with_commitment(signature, CommitmentConfig::default())
|
||||
}
|
||||
|
||||
/// Poll the server to confirm a transaction.
|
||||
@@ -1303,9 +1194,10 @@ impl RpcClient {
|
||||
&self,
|
||||
transaction: &Transaction,
|
||||
) -> ClientResult<Signature> {
|
||||
self.send_and_confirm_transaction_with_spinner_and_commitment(
|
||||
self.send_and_confirm_transaction_with_spinner_and_config(
|
||||
transaction,
|
||||
self.commitment_config,
|
||||
CommitmentConfig::default(),
|
||||
RpcSendTransactionConfig::default(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1317,10 +1209,7 @@ impl RpcClient {
|
||||
self.send_and_confirm_transaction_with_spinner_and_config(
|
||||
transaction,
|
||||
commitment,
|
||||
RpcSendTransactionConfig {
|
||||
preflight_commitment: Some(commitment.commitment),
|
||||
..RpcSendTransactionConfig::default()
|
||||
},
|
||||
RpcSendTransactionConfig::default(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1388,20 +1277,29 @@ impl RpcClient {
|
||||
}
|
||||
let now = Instant::now();
|
||||
loop {
|
||||
// Return when specified commitment is reached
|
||||
// Failed transactions have already been eliminated, `is_some` check is sufficient
|
||||
if self
|
||||
.get_signature_status_with_commitment(&signature, commitment)?
|
||||
.is_some()
|
||||
{
|
||||
progress_bar.set_message("Transaction confirmed");
|
||||
progress_bar.finish_and_clear();
|
||||
return Ok(signature);
|
||||
match commitment.commitment {
|
||||
CommitmentLevel::Max | CommitmentLevel::Root =>
|
||||
// Return when default (max) commitment is reached
|
||||
// Failed transactions have already been eliminated, `is_some` check is sufficient
|
||||
{
|
||||
if self.get_signature_status(&signature)?.is_some() {
|
||||
progress_bar.set_message("Transaction confirmed");
|
||||
progress_bar.finish_and_clear();
|
||||
return Ok(signature);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// Return when one confirmation has been reached
|
||||
if confirmations >= desired_confirmations {
|
||||
progress_bar.set_message("Transaction reached commitment");
|
||||
progress_bar.finish_and_clear();
|
||||
return Ok(signature);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
progress_bar.set_message(&format!(
|
||||
"[{}/{}] Finalizing transaction {}",
|
||||
min(confirmations + 1, desired_confirmations),
|
||||
confirmations + 1,
|
||||
desired_confirmations,
|
||||
signature,
|
||||
));
|
||||
|
@@ -71,21 +71,6 @@ pub struct RpcProgramAccountsConfig {
|
||||
pub account_config: RpcAccountInfoConfig,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum RpcTransactionLogsFilter {
|
||||
All,
|
||||
AllWithVotes,
|
||||
Mentions(Vec<String>), // base58-encoded list of addresses
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcTransactionLogsConfig {
|
||||
#[serde(flatten)]
|
||||
pub commitment: Option<CommitmentConfig>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum RpcTokenAccountsFilter {
|
||||
|
@@ -10,8 +10,6 @@ pub const JSON_RPC_SERVER_ERROR_TRANSACTION_SIGNATURE_VERIFICATION_FAILURE: i64
|
||||
pub const JSON_RPC_SERVER_ERROR_BLOCK_NOT_AVAILABLE: i64 = -32004;
|
||||
pub const JSON_RPC_SERVER_ERROR_NODE_UNHEALTHLY: i64 = -32005;
|
||||
pub const JSON_RPC_SERVER_ERROR_TRANSACTION_PRECOMPILE_VERIFICATION_FAILURE: i64 = -32006;
|
||||
pub const JSON_RPC_SERVER_ERROR_SLOT_SKIPPED: i64 = -32007;
|
||||
pub const JSON_RPC_SERVER_ERROR_LONG_TERM_STORAGE_SLOT_SKIPPED: i64 = -32009;
|
||||
|
||||
pub enum RpcCustomError {
|
||||
BlockCleanedUp {
|
||||
@@ -28,12 +26,6 @@ pub enum RpcCustomError {
|
||||
},
|
||||
RpcNodeUnhealthy,
|
||||
TransactionPrecompileVerificationFailure(solana_sdk::transaction::TransactionError),
|
||||
SlotSkipped {
|
||||
slot: Slot,
|
||||
},
|
||||
LongTermStorageSlotSkipped {
|
||||
slot: Slot,
|
||||
},
|
||||
}
|
||||
|
||||
impl From<RpcCustomError> for Error {
|
||||
@@ -81,19 +73,6 @@ impl From<RpcCustomError> for Error {
|
||||
message: format!("Transaction precompile verification failure {:?}", e),
|
||||
data: None,
|
||||
},
|
||||
RpcCustomError::SlotSkipped { slot } => Self {
|
||||
code: ErrorCode::ServerError(JSON_RPC_SERVER_ERROR_SLOT_SKIPPED),
|
||||
message: format!(
|
||||
"Slot {} was skipped, or missing due to ledger jump to recent snapshot",
|
||||
slot
|
||||
),
|
||||
data: None,
|
||||
},
|
||||
RpcCustomError::LongTermStorageSlotSkipped { slot } => Self {
|
||||
code: ErrorCode::ServerError(JSON_RPC_SERVER_ERROR_LONG_TERM_STORAGE_SLOT_SKIPPED),
|
||||
message: format!("Slot {} was skipped, or missing in long-term storage", slot),
|
||||
data: None,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,4 +1,3 @@
|
||||
use crate::rpc_response::RpcSimulateTransactionResult;
|
||||
use serde_json::{json, Value};
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
use std::fmt;
|
||||
@@ -139,42 +138,12 @@ impl RpcRequest {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum RpcResponseErrorData {
|
||||
Empty,
|
||||
SendTransactionPreflightFailure(RpcSimulateTransactionResult),
|
||||
}
|
||||
|
||||
impl fmt::Display for RpcResponseErrorData {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
RpcResponseErrorData::SendTransactionPreflightFailure(
|
||||
RpcSimulateTransactionResult {
|
||||
logs: Some(logs), ..
|
||||
},
|
||||
) => {
|
||||
if logs.is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
// Give the user a hint that there is more useful logging information available...
|
||||
write!(f, "[{} log messages]", logs.len())
|
||||
}
|
||||
}
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum RpcError {
|
||||
#[error("RPC request error: {0}")]
|
||||
RpcRequestError(String),
|
||||
#[error("RPC response error {code}: {message} {data}")]
|
||||
RpcResponseError {
|
||||
code: i64,
|
||||
message: String,
|
||||
data: RpcResponseErrorData,
|
||||
},
|
||||
#[error("RPC response error {code}: {message}")]
|
||||
RpcResponseError { code: i64, message: String },
|
||||
#[error("parse error: expected {0}")]
|
||||
ParseError(String), /* "expected" */
|
||||
// Anything in a `ForUser` needs to die. The caller should be
|
||||
|
@@ -1,7 +1,7 @@
|
||||
use crate::client_error;
|
||||
use solana_account_decoder::{parse_token::UiTokenAmount, UiAccount};
|
||||
use solana_sdk::{
|
||||
clock::{Epoch, Slot, UnixTimestamp},
|
||||
clock::{Epoch, Slot},
|
||||
fee_calculator::{FeeCalculator, FeeRateGovernor},
|
||||
inflation::Inflation,
|
||||
transaction::{Result, TransactionError},
|
||||
@@ -108,14 +108,6 @@ pub enum RpcSignatureResult {
|
||||
ReceivedSignature(ReceivedSignatureResult),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcLogsResponse {
|
||||
pub signature: String, // Signature as base58 string
|
||||
pub err: Option<TransactionError>,
|
||||
pub logs: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ProcessedSignatureResult {
|
||||
@@ -286,7 +278,6 @@ pub struct RpcConfirmedTransactionStatusWithSignature {
|
||||
pub slot: Slot,
|
||||
pub err: Option<TransactionError>,
|
||||
pub memo: Option<String>,
|
||||
pub block_time: Option<UnixTimestamp>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
@@ -305,14 +296,12 @@ impl From<ConfirmedTransactionStatusWithSignature> for RpcConfirmedTransactionSt
|
||||
slot,
|
||||
err,
|
||||
memo,
|
||||
block_time,
|
||||
} = value;
|
||||
Self {
|
||||
signature: signature.to_string(),
|
||||
slot,
|
||||
err,
|
||||
memo,
|
||||
block_time,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@
|
||||
//! messages to the network directly. The binary encoding of its messages are
|
||||
//! unstable and may change in future releases.
|
||||
|
||||
use crate::{rpc_client::RpcClient, rpc_config::RpcProgramAccountsConfig, rpc_response::Response};
|
||||
use crate::{rpc_client::RpcClient, rpc_response::Response};
|
||||
use bincode::{serialize_into, serialized_size};
|
||||
use log::*;
|
||||
use solana_sdk::{
|
||||
@@ -276,16 +276,6 @@ impl ThinClient {
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_program_accounts_with_config(
|
||||
&self,
|
||||
pubkey: &Pubkey,
|
||||
config: RpcProgramAccountsConfig,
|
||||
) -> TransportResult<Vec<(Pubkey, Account)>> {
|
||||
self.rpc_client()
|
||||
.get_program_accounts_with_config(pubkey, config)
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
|
||||
pub fn wait_for_balance_with_commitment(
|
||||
&self,
|
||||
pubkey: &Pubkey,
|
||||
@@ -399,12 +389,6 @@ impl SyncClient for ThinClient {
|
||||
.map(|r| r.value)
|
||||
}
|
||||
|
||||
fn get_minimum_balance_for_rent_exemption(&self, data_len: usize) -> TransportResult<u64> {
|
||||
self.rpc_client()
|
||||
.get_minimum_balance_for_rent_exemption(data_len)
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
|
||||
fn get_recent_blockhash(&self) -> TransportResult<(Hash, FeeCalculator)> {
|
||||
let (blockhash, fee_calculator, _last_valid_slot) =
|
||||
self.get_recent_blockhash_with_commitment(CommitmentConfig::default())?;
|
||||
|
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "solana-core"
|
||||
description = "Blockchain, Rebuilt for Scale"
|
||||
version = "1.4.26"
|
||||
version = "1.3.24"
|
||||
documentation = "https://docs.rs/solana"
|
||||
homepage = "https://solana.com/"
|
||||
readme = "../README.md"
|
||||
@@ -14,7 +14,6 @@ edition = "2018"
|
||||
codecov = { repository = "solana-labs/solana", branch = "master", service = "github" }
|
||||
|
||||
[dependencies]
|
||||
ahash = "0.6.1"
|
||||
base64 = "0.12.3"
|
||||
bincode = "1.3.1"
|
||||
bv = { version = "0.11.1", features = ["serde"] }
|
||||
@@ -38,56 +37,53 @@ log = "0.4.8"
|
||||
lru = "0.6.0"
|
||||
miow = "0.2.2"
|
||||
net2 = "0.2.37"
|
||||
num_cpus = "1.13.0"
|
||||
num-traits = "0.2"
|
||||
rand = "0.7.0"
|
||||
rand_chacha = "0.2.2"
|
||||
raptorq = "1.4.2"
|
||||
rayon = "1.4.1"
|
||||
rayon = "1.4.0"
|
||||
regex = "1.3.9"
|
||||
rustversion = "1.0.4"
|
||||
serde = "1.0.112"
|
||||
serde_derive = "1.0.103"
|
||||
serde_json = "1.0.56"
|
||||
solana-account-decoder = { path = "../account-decoder", version = "1.4.26" }
|
||||
solana-banks-server = { path = "../banks-server", version = "1.4.26" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.4.26" }
|
||||
solana-client = { path = "../client", version = "1.4.26" }
|
||||
solana-faucet = { path = "../faucet", version = "1.4.26" }
|
||||
solana-frozen-abi = { path = "../frozen-abi", version = "1.4.26" }
|
||||
solana-frozen-abi-macro = { path = "../frozen-abi/macro", version = "1.4.26" }
|
||||
solana-ledger = { path = "../ledger", version = "1.4.26" }
|
||||
solana-logger = { path = "../logger", version = "1.4.26" }
|
||||
solana-merkle-tree = { path = "../merkle-tree", version = "1.4.26" }
|
||||
solana-metrics = { path = "../metrics", version = "1.4.26" }
|
||||
solana-measure = { path = "../measure", version = "1.4.26" }
|
||||
solana-net-utils = { path = "../net-utils", version = "1.4.26" }
|
||||
solana-perf = { path = "../perf", version = "1.4.26" }
|
||||
solana-runtime = { path = "../runtime", version = "1.4.26" }
|
||||
solana-sdk = { path = "../sdk", version = "1.4.26" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "1.4.26" }
|
||||
solana-storage-bigtable = { path = "../storage-bigtable", version = "1.4.26" }
|
||||
solana-streamer = { path = "../streamer", version = "1.4.26" }
|
||||
solana-sys-tuner = { path = "../sys-tuner", version = "1.4.26" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "1.4.26" }
|
||||
solana-version = { path = "../version", version = "1.4.26" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "1.4.26" }
|
||||
solana-vote-signer = { path = "../vote-signer", version = "1.4.26" }
|
||||
spl-token-v2-0 = { package = "spl-token", version = "=3.0.1", features = ["no-entrypoint"] }
|
||||
solana-account-decoder = { path = "../account-decoder", version = "1.3.24" }
|
||||
solana-banks-server = { path = "../banks-server", version = "1.3.24" }
|
||||
solana-budget-program = { path = "../programs/budget", version = "1.3.24" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.3.24" }
|
||||
solana-client = { path = "../client", version = "1.3.24" }
|
||||
solana-faucet = { path = "../faucet", version = "1.3.24" }
|
||||
solana-ledger = { path = "../ledger", version = "1.3.24" }
|
||||
solana-logger = { path = "../logger", version = "1.3.24" }
|
||||
solana-merkle-tree = { path = "../merkle-tree", version = "1.3.24" }
|
||||
solana-metrics = { path = "../metrics", version = "1.3.24" }
|
||||
solana-measure = { path = "../measure", version = "1.3.24" }
|
||||
solana-net-utils = { path = "../net-utils", version = "1.3.24" }
|
||||
solana-perf = { path = "../perf", version = "1.3.24" }
|
||||
solana-runtime = { path = "../runtime", version = "1.3.24" }
|
||||
solana-sdk = { path = "../sdk", version = "1.3.24" }
|
||||
solana-sdk-macro-frozen-abi = { path = "../sdk/macro-frozen-abi", version = "1.3.24" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "1.3.24" }
|
||||
solana-storage-bigtable = { path = "../storage-bigtable", version = "1.3.24" }
|
||||
solana-streamer = { path = "../streamer", version = "1.3.24" }
|
||||
solana-sys-tuner = { path = "../sys-tuner", version = "1.3.24" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "1.3.24" }
|
||||
solana-version = { path = "../version", version = "1.3.24" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "1.3.24" }
|
||||
solana-vote-signer = { path = "../vote-signer", version = "1.3.24" }
|
||||
spl-token-v2-0 = { package = "spl-token", version = "=2.0.6", features = ["skip-no-mangle"] }
|
||||
tempfile = "3.1.0"
|
||||
thiserror = "1.0"
|
||||
tokio = { version = "0.2", features = ["full"] }
|
||||
tokio_01 = { version = "0.1", package = "tokio" }
|
||||
tokio_01_bytes = { version = "0.4.7", package = "bytes" }
|
||||
tokio_fs_01 = { version = "0.1", package = "tokio-fs" }
|
||||
tokio_io_01 = { version = "0.1", package = "tokio-io" }
|
||||
tokio_codec_01 = { version = "0.1", package = "tokio-codec" }
|
||||
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "1.4.26" }
|
||||
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "1.3.24" }
|
||||
tokio = { version = "0.2.22", features = ["full"] }
|
||||
trees = "0.2.1"
|
||||
|
||||
[dev-dependencies]
|
||||
matches = "0.1.6"
|
||||
num_cpus = "1.13.0"
|
||||
reqwest = { version = "0.10.8", default-features = false, features = ["blocking", "rustls-tls", "json"] }
|
||||
reqwest = { version = "0.10.6", default-features = false, features = ["blocking", "rustls-tls", "json"] }
|
||||
serial_test = "0.4.0"
|
||||
serial_test_derive = "0.4.0"
|
||||
systemstat = "0.1.5"
|
||||
|
@@ -20,7 +20,6 @@ use solana_runtime::bank::Bank;
|
||||
use solana_sdk::genesis_config::GenesisConfig;
|
||||
use solana_sdk::hash::Hash;
|
||||
use solana_sdk::message::Message;
|
||||
use solana_sdk::pubkey;
|
||||
use solana_sdk::signature::Keypair;
|
||||
use solana_sdk::signature::Signature;
|
||||
use solana_sdk::signature::Signer;
|
||||
@@ -56,7 +55,7 @@ fn bench_consume_buffered(bencher: &mut Bencher) {
|
||||
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(100_000);
|
||||
let bank = Arc::new(Bank::new(&genesis_config));
|
||||
let ledger_path = get_tmp_ledger_path!();
|
||||
let my_pubkey = pubkey::new_rand();
|
||||
let my_pubkey = solana_sdk::pubkey::new_rand();
|
||||
{
|
||||
let blockstore = Arc::new(
|
||||
Blockstore::open(&ledger_path).expect("Expected to be able to open database ledger"),
|
||||
@@ -94,22 +93,21 @@ fn bench_consume_buffered(bencher: &mut Bencher) {
|
||||
}
|
||||
|
||||
fn make_accounts_txs(txes: usize, mint_keypair: &Keypair, hash: Hash) -> Vec<Transaction> {
|
||||
let to_pubkey = pubkey::new_rand();
|
||||
let to_pubkey = solana_sdk::pubkey::new_rand();
|
||||
let dummy = system_transaction::transfer(mint_keypair, &to_pubkey, 1, hash);
|
||||
(0..txes)
|
||||
.into_par_iter()
|
||||
.map(|_| {
|
||||
let mut new = dummy.clone();
|
||||
let sig: Vec<u8> = (0..64).map(|_| thread_rng().gen()).collect();
|
||||
new.message.account_keys[0] = pubkey::new_rand();
|
||||
new.message.account_keys[1] = pubkey::new_rand();
|
||||
new.message.account_keys[0] = solana_sdk::pubkey::new_rand();
|
||||
new.message.account_keys[1] = solana_sdk::pubkey::new_rand();
|
||||
new.signatures = vec![Signature::new(&sig[0..64])];
|
||||
new
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[allow(clippy::same_item_push)]
|
||||
fn make_programs_txs(txes: usize, hash: Hash) -> Vec<Transaction> {
|
||||
let progs = 4;
|
||||
(0..txes)
|
||||
@@ -117,7 +115,7 @@ fn make_programs_txs(txes: usize, hash: Hash) -> Vec<Transaction> {
|
||||
let mut instructions = vec![];
|
||||
let from_key = Keypair::new();
|
||||
for _ in 1..progs {
|
||||
let to_key = pubkey::new_rand();
|
||||
let to_key = solana_sdk::pubkey::new_rand();
|
||||
instructions.push(system_instruction::transfer(&from_key.pubkey(), &to_key, 1));
|
||||
}
|
||||
let message = Message::new(&instructions, Some(&from_key.pubkey()));
|
||||
@@ -295,7 +293,6 @@ fn simulate_process_entries(
|
||||
process_entries(&bank, &[entry], randomize_txs, None, None).unwrap();
|
||||
}
|
||||
|
||||
#[allow(clippy::same_item_push)]
|
||||
fn bench_process_entries(randomize_txs: bool, bencher: &mut Bencher) {
|
||||
// entropy multiplier should be big enough to provide sufficient entropy
|
||||
// but small enough to not take too much time while executing the test.
|
||||
|
@@ -8,7 +8,6 @@ use solana_core::broadcast_stage::{broadcast_shreds, get_broadcast_peers};
|
||||
use solana_core::cluster_info::{ClusterInfo, Node};
|
||||
use solana_core::contact_info::ContactInfo;
|
||||
use solana_ledger::shred::Shred;
|
||||
use solana_sdk::pubkey;
|
||||
use solana_sdk::timing::timestamp;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
@@ -20,7 +19,7 @@ use test::Bencher;
|
||||
#[bench]
|
||||
fn broadcast_shreds_bench(bencher: &mut Bencher) {
|
||||
solana_logger::setup();
|
||||
let leader_pubkey = pubkey::new_rand();
|
||||
let leader_pubkey = solana_sdk::pubkey::new_rand();
|
||||
let leader_info = Node::new_localhost_with_pubkey(&leader_pubkey);
|
||||
let cluster_info = ClusterInfo::new_with_invalid_keypair(leader_info.info);
|
||||
let socket = UdpSocket::bind("0.0.0.0:0").unwrap();
|
||||
@@ -30,7 +29,7 @@ fn broadcast_shreds_bench(bencher: &mut Bencher) {
|
||||
let mut stakes = HashMap::new();
|
||||
const NUM_PEERS: usize = 200;
|
||||
for _ in 0..NUM_PEERS {
|
||||
let id = pubkey::new_rand();
|
||||
let id = solana_sdk::pubkey::new_rand();
|
||||
let contact_info = ContactInfo::new_localhost(&id, timestamp());
|
||||
cluster_info.insert_info(contact_info);
|
||||
stakes.insert(id, thread_rng().gen_range(1, NUM_PEERS) as u64);
|
||||
|
@@ -1,36 +0,0 @@
|
||||
#![feature(test)]
|
||||
|
||||
extern crate solana_core;
|
||||
extern crate test;
|
||||
|
||||
use solana_core::consensus::Tower;
|
||||
use solana_runtime::bank::Bank;
|
||||
use solana_runtime::bank_forks::BankForks;
|
||||
use solana_sdk::{
|
||||
pubkey::Pubkey,
|
||||
signature::{Keypair, Signer},
|
||||
};
|
||||
use std::sync::Arc;
|
||||
use tempfile::TempDir;
|
||||
use test::Bencher;
|
||||
|
||||
#[bench]
|
||||
fn bench_save_tower(bench: &mut Bencher) {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let path = dir.path();
|
||||
|
||||
let vote_account_pubkey = &Pubkey::default();
|
||||
let node_keypair = Arc::new(Keypair::new());
|
||||
let heaviest_bank = BankForks::new(Bank::default()).working_bank();
|
||||
let tower = Tower::new(
|
||||
&node_keypair.pubkey(),
|
||||
&vote_account_pubkey,
|
||||
0,
|
||||
&heaviest_bank,
|
||||
&path,
|
||||
);
|
||||
|
||||
bench.iter(move || {
|
||||
tower.save(&node_keypair).unwrap();
|
||||
});
|
||||
}
|
@@ -17,7 +17,7 @@ fn bench_find_old_labels(bencher: &mut Bencher) {
|
||||
let mut rng = thread_rng();
|
||||
let mut crds = Crds::default();
|
||||
let now = CRDS_GOSSIP_PULL_CRDS_TIMEOUT_MS + CRDS_GOSSIP_PULL_CRDS_TIMEOUT_MS / 1000;
|
||||
std::iter::repeat_with(|| (CrdsValue::new_rand(&mut rng, None), rng.gen_range(0, now)))
|
||||
std::iter::repeat_with(|| (CrdsValue::new_rand(&mut rng), rng.gen_range(0, now)))
|
||||
.take(50_000)
|
||||
.for_each(|(v, ts)| assert!(crds.insert(v, ts).is_ok()));
|
||||
let mut timeouts = HashMap::new();
|
||||
|
@@ -8,13 +8,12 @@ use solana_core::cluster_info::MAX_BLOOM_SIZE;
|
||||
use solana_core::crds::Crds;
|
||||
use solana_core::crds_gossip_pull::{CrdsFilter, CrdsGossipPull};
|
||||
use solana_core::crds_value::CrdsValue;
|
||||
use solana_sdk::hash;
|
||||
use test::Bencher;
|
||||
|
||||
#[bench]
|
||||
fn bench_hash_as_u64(bencher: &mut Bencher) {
|
||||
let mut rng = thread_rng();
|
||||
let hashes: Vec<_> = std::iter::repeat_with(|| hash::new_rand(&mut rng))
|
||||
let hashes: Vec<_> = std::iter::repeat_with(|| solana_sdk::hash::new_rand(&mut rng))
|
||||
.take(1000)
|
||||
.collect();
|
||||
bencher.iter(|| {
|
||||
@@ -39,7 +38,7 @@ fn bench_build_crds_filters(bencher: &mut Bencher) {
|
||||
let mut num_inserts = 0;
|
||||
for _ in 0..90_000 {
|
||||
if crds
|
||||
.insert(CrdsValue::new_rand(&mut rng, None), rng.gen())
|
||||
.insert(CrdsValue::new_rand(&mut rng), rng.gen())
|
||||
.is_ok()
|
||||
{
|
||||
num_inserts += 1;
|
||||
|
@@ -7,14 +7,16 @@ use solana_core::contact_info::ContactInfo;
|
||||
use solana_core::crds::VersionedCrdsValue;
|
||||
use solana_core::crds_shards::CrdsShards;
|
||||
use solana_core::crds_value::{CrdsData, CrdsValue};
|
||||
use solana_sdk::pubkey;
|
||||
use solana_sdk::timing::timestamp;
|
||||
use test::Bencher;
|
||||
|
||||
const CRDS_SHARDS_BITS: u32 = 8;
|
||||
|
||||
fn new_test_crds_value() -> VersionedCrdsValue {
|
||||
let data = CrdsData::ContactInfo(ContactInfo::new_localhost(&pubkey::new_rand(), timestamp()));
|
||||
let data = CrdsData::ContactInfo(ContactInfo::new_localhost(
|
||||
&solana_sdk::pubkey::new_rand(),
|
||||
timestamp(),
|
||||
));
|
||||
VersionedCrdsValue::new(timestamp(), CrdsValue::new_unsigned(data))
|
||||
}
|
||||
|
||||
|
@@ -7,18 +7,13 @@ use log::*;
|
||||
use solana_core::cluster_info::{ClusterInfo, Node};
|
||||
use solana_core::contact_info::ContactInfo;
|
||||
use solana_core::retransmit_stage::retransmitter;
|
||||
use solana_ledger::entry::Entry;
|
||||
use solana_ledger::genesis_utils::{create_genesis_config, GenesisConfigInfo};
|
||||
use solana_ledger::leader_schedule_cache::LeaderScheduleCache;
|
||||
use solana_ledger::shred::Shredder;
|
||||
use solana_measure::measure::Measure;
|
||||
use solana_perf::packet::{Packet, Packets};
|
||||
use solana_perf::packet::to_packets_chunked;
|
||||
use solana_perf::test_tx::test_tx;
|
||||
use solana_runtime::bank::Bank;
|
||||
use solana_runtime::bank_forks::BankForks;
|
||||
use solana_sdk::hash::Hash;
|
||||
use solana_sdk::pubkey;
|
||||
use solana_sdk::signature::{Keypair, Signer};
|
||||
use solana_sdk::system_transaction;
|
||||
use solana_sdk::timing::timestamp;
|
||||
use std::net::UdpSocket;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
@@ -31,14 +26,13 @@ use std::time::Duration;
|
||||
use test::Bencher;
|
||||
|
||||
#[bench]
|
||||
#[allow(clippy::same_item_push)]
|
||||
fn bench_retransmitter(bencher: &mut Bencher) {
|
||||
solana_logger::setup();
|
||||
let cluster_info = ClusterInfo::new_with_invalid_keypair(Node::new_localhost().info);
|
||||
const NUM_PEERS: usize = 4;
|
||||
let mut peer_sockets = Vec::new();
|
||||
for _ in 0..NUM_PEERS {
|
||||
let id = pubkey::new_rand();
|
||||
let id = solana_sdk::pubkey::new_rand();
|
||||
let socket = UdpSocket::bind("0.0.0.0:0").unwrap();
|
||||
let mut contact_info = ContactInfo::new_localhost(&id, timestamp());
|
||||
contact_info.tvu = socket.local_addr().unwrap();
|
||||
@@ -67,24 +61,14 @@ fn bench_retransmitter(bencher: &mut Bencher) {
|
||||
let leader_schedule_cache = Arc::new(LeaderScheduleCache::new_from_bank(&bank));
|
||||
|
||||
// To work reliably with higher values, this needs larger udp rmem size
|
||||
let entries: Vec<_> = (0..5)
|
||||
.map(|_| {
|
||||
let keypair0 = Keypair::new();
|
||||
let keypair1 = Keypair::new();
|
||||
let tx0 =
|
||||
system_transaction::transfer(&keypair0, &keypair1.pubkey(), 1, Hash::default());
|
||||
Entry::new(&Hash::default(), 1, vec![tx0])
|
||||
})
|
||||
.collect();
|
||||
|
||||
let keypair = Arc::new(Keypair::new());
|
||||
let slot = 0;
|
||||
let parent = 0;
|
||||
let shredder =
|
||||
Shredder::new(slot, parent, 0.0, keypair, 0, 0).expect("Failed to create entry shredder");
|
||||
let mut data_shreds = shredder.entries_to_shreds(&entries, true, 0).0;
|
||||
|
||||
let num_packets = data_shreds.len();
|
||||
let tx = test_tx();
|
||||
const NUM_PACKETS: usize = 50;
|
||||
let chunk_size = NUM_PACKETS / (4 * NUM_THREADS);
|
||||
let batches = to_packets_chunked(
|
||||
&std::iter::repeat(tx).take(NUM_PACKETS).collect::<Vec<_>>(),
|
||||
chunk_size,
|
||||
);
|
||||
info!("batches: {}", batches.len());
|
||||
|
||||
let retransmitter_handles = retransmitter(
|
||||
Arc::new(sockets),
|
||||
@@ -94,8 +78,6 @@ fn bench_retransmitter(bencher: &mut Bencher) {
|
||||
packet_receiver,
|
||||
);
|
||||
|
||||
let mut index = 0;
|
||||
let mut slot = 0;
|
||||
let total = Arc::new(AtomicUsize::new(0));
|
||||
bencher.iter(move || {
|
||||
let peer_sockets1 = peer_sockets.clone();
|
||||
@@ -112,7 +94,7 @@ fn bench_retransmitter(bencher: &mut Bencher) {
|
||||
while peer_sockets2[p].recv(&mut buf).is_ok() {
|
||||
total2.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
if total2.load(Ordering::Relaxed) >= num_packets {
|
||||
if total2.load(Ordering::Relaxed) >= NUM_PACKETS {
|
||||
break;
|
||||
}
|
||||
info!("{} recv", total2.load(Ordering::Relaxed));
|
||||
@@ -123,17 +105,9 @@ fn bench_retransmitter(bencher: &mut Bencher) {
|
||||
})
|
||||
.collect();
|
||||
|
||||
for shred in data_shreds.iter_mut() {
|
||||
shred.set_slot(slot);
|
||||
shred.set_index(index);
|
||||
index += 1;
|
||||
index %= 200;
|
||||
let mut p = Packet::default();
|
||||
shred.copy_to_packet(&mut p);
|
||||
let _ = packet_sender.send(Packets::new(vec![p]));
|
||||
for packets in batches.clone() {
|
||||
packet_sender.send(packets).unwrap();
|
||||
}
|
||||
slot += 1;
|
||||
|
||||
info!("sent...");
|
||||
|
||||
let mut join_time = Measure::start("join");
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user