Compare commits

..

21 Commits

Author SHA1 Message Date
mergify[bot]
c54b23b9d5 Additional tests for should_retransmit_and_persist (#6062) (#6070)
automerge
2019-09-24 17:48:39 -07:00
mergify[bot]
04aaa714e6 Revert back to reqwest, using rustls feature (bp #6041) (#6064)
automerge
2019-09-24 15:35:07 -07:00
Michael Vines
2cc0ab2c5f Tweak Bank Slot Distance graph 2019-09-24 14:52:50 -07:00
mergify[bot]
aac0d7f2f5 Window service is filtering out coding shreds (#6052) (#6059)
automerge
2019-09-24 13:48:13 -07:00
mergify[bot]
9fd29b0575 Fix vote metrics (#6038) (#6040)
automerge
2019-09-24 13:20:27 -07:00
mergify[bot]
6abe3c2804 Fix race between observing tick height being set to last tick and blockhash being observed on a bank (#6013) (#6056)
automerge
2019-09-24 12:20:46 -07:00
mergify[bot]
01ce5beb19 Support primordial accounts with no data (#6053) (#6055)
automerge
2019-09-24 11:52:57 -07:00
mergify[bot]
2bd72318f6 Remove dead code from cluster_info (#6051) (#6054)
automerge
2019-09-24 11:29:52 -07:00
carllin
68a9224604 Fix race between observing tick height being set to last tick and blockhash being observed on a bank (#6013) 2019-09-24 11:16:24 -07:00
Rob Walker
181cad233c rename balance (#5984) 2019-09-24 11:15:15 -07:00
Justin Starry
0b66529f11 Fix BPF program static linking (#5992) (#6049)
automerge
2019-09-24 09:40:33 -07:00
Michael Vines
e20e4180a9 Flip order of arg to ensure -t sticks 2019-09-23 22:21:12 -07:00
mergify[bot]
de4309a905 Avoid hardlinking as that confuses tar (#6042) (#6045)
(cherry picked from commit 7fa809c16d)
2019-09-23 21:40:09 -07:00
mergify[bot]
d5248c936f Skip considering banks older than the latest vote slot (#6037) (#6043)
automerge
2019-09-23 20:44:47 -07:00
mergify[bot]
40bc37266d Don't recover coding shreds (#6034) (#6039)
automerge
2019-09-23 18:35:50 -07:00
mergify[bot]
1819f263f1 ' => " (#6035) (#6036)
automerge
2019-09-23 17:31:05 -07:00
Pankaj Garg
24a055e490 Upgrade to ReedSolomon 4.0 release (#6026) (#6030)
automerge
2019-09-23 15:29:52 -07:00
mergify[bot]
dfbd77f18d Fix really old banks triggering log spam (#6025) (#6029)
automerge
2019-09-23 15:27:38 -07:00
mergify[bot]
7c5557d69b Dump tar stdout/err on failure for better debug (#6024) (#6027)
automerge
2019-09-23 13:57:39 -07:00
mergify[bot]
d180eedd17 Remove the _/deps symlink, just copy instead (#6020) (#6021)
automerge
2019-09-23 09:50:07 -07:00
Michael Vines
3b274ca8db GitBook: [v0.19] 79 pages and 12 assets modified 2019-09-23 03:38:36 +00:00
1176 changed files with 74120 additions and 147387 deletions

42
.appveyor.yml Normal file
View File

@@ -0,0 +1,42 @@
version: '{build}'
branches:
only:
- master
- /^v[0-9.]+\.[0-9.]+/
cache:
- '%USERPROFILE%\.cargo'
- '%APPVEYOR_BUILD_FOLDER%\target'
clone_folder: d:\projects\solana
build_script:
- bash ci/publish-tarball.sh
notifications:
- provider: Slack
incoming_webhook:
secure: GJsBey+F5apAtUm86MHVJ68Uqa6WN1SImcuIc4TsTZrDhA8K1QWUNw9FFQPybUWDyOcS5dly3kubnUqlGt9ux6Ad2efsfRIQYWv0tOVXKeY=
channel: ci-status
on_build_success: false
on_build_failure: true
on_build_status_changed: true
deploy:
- provider: S3
access_key_id:
secure: fTbJl6JpFebR40J7cOWZ2mXBa3kIvEiXgzxAj6L3N7A=
secret_access_key:
secure: vItsBXb2rEFLvkWtVn/Rcxu5a5+2EwC+b7GsA0waJy9hXh6XuBAD0lnHd9re3g/4
bucket: release.solana.com
region: us-west-1
set_public: true
- provider: GitHub
auth_token:
secure: 81fEmPZ0cV1wLtNuUrcmtgxKF6ROQF1+/ft5m+fHX21z6PoeCbaNo8cTyLioWBj7
draft: false
prerelease: false
on:
appveyor_repo_tag: true

View File

@@ -1,12 +1,14 @@
{ {
"_public_key": "ae29f4f7ad2fc92de70d470e411c8426d5d48db8817c9e3dae574b122192335f", "_public_key": "ae29f4f7ad2fc92de70d470e411c8426d5d48db8817c9e3dae574b122192335f",
"environment": { "environment": {
"CODECOV_TOKEN": "EJ[1:Z7OneT3RdJJ0DipCHQ7rC84snQ+FPbgHwZADQiz54wk=:3K68mE38LJ2RB98VWmjuNLFBNn1XTGR4:cR4r05/TOZQKmEZp1v4CSgUJtC6QJiOaL85QjXW0qZ061fMnsBA8AtAPMDoDq4WCGOZM1A==]", "CODECOV_TOKEN": "EJ[1:8iZ6baJB4fbBV+XDsrUooyGAnGL/8Ol+4Qd0zKh5YjI=:ks2/ElgxwgxqgmFcxTHANNLmj23YH74h:U4uzRONRfiQyqy6HrPQ/e7OnBUY4HkW37R0iekkF3KJ9UGnHqT1UvwgVbDqLahtDIJ4rWw==]",
"CRATES_IO_TOKEN": "EJ[1:Z7OneT3RdJJ0DipCHQ7rC84snQ+FPbgHwZADQiz54wk=:GGRTYDjMXksevzR6kq4Jx+FaIQZz50RU:xkbwDxcgoCyU+aT2tiI9mymigrEl6YiOr3axe3aX70ELIBKbCdPGilXP/wixvKi94g2u]", "CRATES_IO_TOKEN": "EJ[1:8iZ6baJB4fbBV+XDsrUooyGAnGL/8Ol+4Qd0zKh5YjI=:lKMh3aLW+jyRrfS/c7yvkpB+TaPhXqLq:j0v27EbaPgwRdHZAbsM0FlAnt3r9ScQrFbWJYOAZtM3qestEiByTlKpZ0eyF/823]",
"GEOLOCATION_API_KEY": "EJ[1:Z7OneT3RdJJ0DipCHQ7rC84snQ+FPbgHwZADQiz54wk=:U2PZLi5MU3Ru/zK1SilianEeizcMvxml:AJKf2OAtDHmJh0KyXrBnNnistItZvVVP3cZ7ZLtrVupjmWN/PzmKwSsXeCNObWS+]", "GITHUB_TOKEN": "EJ[1:8iZ6baJB4fbBV+XDsrUooyGAnGL/8Ol+4Qd0zKh5YjI=:Ll78c3jGpYqnTwR7HJq3mNNUC7pOv9Lu:GrInO2r8MjmP5c54szkyygdsrW5KQYkDgJQUVyFEPyG8SWfchyM9Gur8RV0a+cdwuxNkHLi4U2M=]",
"GITHUB_TOKEN": "EJ[1:Z7OneT3RdJJ0DipCHQ7rC84snQ+FPbgHwZADQiz54wk=:0NJNlpD/O19mvOakCGBYDhIDfySxWFSC:Dz4NXv9x6ncRQ1u9sVoWOcqmkg0sI09qmefghB0GXZgPcFGgn6T0mw7ynNnbUvjyH8dLruKHauk=]", "INFLUX_DATABASE": "EJ[1:8iZ6baJB4fbBV+XDsrUooyGAnGL/8Ol+4Qd0zKh5YjI=:IlH/ZLTXv3SwlY3TVyAPCX2KzLRY6iG3:gGmUGSU/kCfR/mTwKONaUC/X]",
"INFLUX_DATABASE": "EJ[1:Z7OneT3RdJJ0DipCHQ7rC84snQ+FPbgHwZADQiz54wk=:SzwHIeOVpmbTcGQOGngoFgYumsLZJUGq:t7Rpk49njsWvoM+ztv5Uwuiz]", "INFLUX_PASSWORD": "EJ[1:8iZ6baJB4fbBV+XDsrUooyGAnGL/8Ol+4Qd0zKh5YjI=:o2qm95GU4VrrcC4OU06jjPvCwKZy/CZF:OW2ga3kLOQJvaDEdGRJ+gn3L2ckFm8AJZtv9wj/GeUIKDH2A4uBPTHsAH9PMe6zujpuHGk3qbeg=]",
"INFLUX_PASSWORD": "EJ[1:Z7OneT3RdJJ0DipCHQ7rC84snQ+FPbgHwZADQiz54wk=:/MUs+q7pdGrUjzwcq+6pgIFxur4hxdqu:am22z2E2dtmw1f1J1Mq5JLcUHZsrEjQAJ0pp21M4AZeJbNO6bVb44d9zSkHj7xdN6U+GNlCk+wU=]", "INFLUX_USERNAME": "EJ[1:8iZ6baJB4fbBV+XDsrUooyGAnGL/8Ol+4Qd0zKh5YjI=:yDWW/uIHsJqOTDYskZoSx3pzoB1vztWY:2z31oTA3g0Xs9fCczGNJRcx8xf/hFCed]",
"INFLUX_USERNAME": "EJ[1:Z7OneT3RdJJ0DipCHQ7rC84snQ+FPbgHwZADQiz54wk=:XjghH20xGVWro9B+epGlJaJcW8Wze0Bi:ZIdOtXudTY5TqKseDU7gVvQXfmXV99Xh]" "SOLANA_INSTALL_UPDATE_MANIFEST_KEYPAIR_x86_64_unknown_linux_gnu": "EJ[1:8iZ6baJB4fbBV+XDsrUooyGAnGL/8Ol+4Qd0zKh5YjI=:RqRaHlYUvGPNFJa6gmciaYM3tRJTURUH:q78/3GTHCN3Uqx9z4nOBjPZcO1lOazNoB/mdhGRDFsnAqVd2hU8zbKkqLrZfLlGqyD8WQOFuw5oTJR9qWg6L9LcOyj3pGL8jWF2yjgZxdtNMXnkbSrCWLooWBBLT61jYQnEwg73gT8ld3Q8EVv3T+MeSMu6FnPz+0+bqQCAGgfqksP4hsUAJGzgZu+i0tNOdlT7fxnh5KJK/yFM/CKgN2sRwEjukA9hXsffyB61g2zqzTDJxCUDLbCVrCkA/bfUk7Of/t0W5t0nK1H3oyGZEc/lRMauCknDBka3Gz11dVss2QT19WQNh0u7bHVaT/U4lepX1j9Zv]",
"SOLANA_INSTALL_UPDATE_MANIFEST_KEYPAIR_x86_64_apple_darwin": "EJ[1:8iZ6baJB4fbBV+XDsrUooyGAnGL/8Ol+4Qd0zKh5YjI=:wFDl3INEnA3EQDHRX40avqGe1OMoJxyy:6ncCRVRTIRuYI5o/gayeuWCudWvmKNYr8KEHAWeTq34a5bdcKInBdKhjmjX+wLHqsEwQ5gcyhcxy4Ri2mbuN6AHazfZOZlubQkGlyUOAIYO5D5jkbyIh40DAtjVzo1MD/0HsW9zdGOzqUKp5xJJeDsbR4F153jbxa7fvwF90Q4UQjYFTKAtExEmHtDGSJG48ToVwTabTV/OnISMIggDZBviIv2QWHvXgK07b2mUj34rHJywEDGN1nj5rITTDdUeRcB1x4BAMOe94kTFPSTaj/OszvYlGECt8rkKFqbm092qL+XLfiBaImqe/WJHRCnAj6Don]",
"SOLANA_INSTALL_UPDATE_MANIFEST_KEYPAIR_x86_64_pc_windows_msvc": "EJ[1:8iZ6baJB4fbBV+XDsrUooyGAnGL/8Ol+4Qd0zKh5YjI=:wAh+dBuZopv6vruVOYegUcq/aBnbksT1:qIJfCfDvDWiqicMOkmbJs/0n7UJLKNmgMQaKzeQ8J7Q60YpXbtWzKVW3tS6lzlgf64m3MrPXyo1C+mWh6jkjsb18T/OfggZy1ZHM4AcsOC6/ldUkV5YtuxUQuAmd5jCuV/R7iuYY8Z66AcfAevlb+bnLpgIifdA8fh/IktOo58nZUQwZDdppAacmftsLc6Frn5Er6A6+EXpxK1nmnlmLJ4AJztqlh6X0r+JvE2O7qeoZUXrIegnkxo7Aay7I/dd8zdYpp7ICSiTEtfVN/xNIu/5QmTRU7gWoz7cPl9epq4aiEALzPOzb6KVOiRcsOg+TlFvLQ71Ik5o=]"
} }
} }

View File

@@ -1,18 +1,5 @@
root: ./docs/src root: ./book/src
structure: structure:
readme: introduction.md readme: introduction.md
summary: SUMMARY.md summary: SUMMARY.md
redirects:
wallet: ./wallet-guide/README.md
wallet/app-wallets: ./wallet-guide/apps.md
wallet/app-wallets/trust-wallet: ./wallet-guide/trust-wallet.md
wallet/app-wallets/ledger-live: ./wallet-guide/ledger-live.md
wallet/cli-wallets: ./wallet-guide/cli.md
wallet/cli-wallets/paper-wallet: ./paper-wallet/README.md
wallet/cli-wallets/paper-wallet/paper-wallet-usage: ./paper-wallet/paper-wallet-usage.md
wallet/cli-wallets/remote-wallet: ./hardware-wallets/README.md
wallet/cli-wallets/remote-wallet/ledger: ./hardware-wallets/ledger.md
wallet/cli-wallets/file-system-wallet: ./file-system-wallet/README.md
wallet/support: ./wallet-guide/support.md

2
.github/stale.yml vendored
View File

@@ -1,7 +1,7 @@
only: pulls only: pulls
# Number of days of inactivity before a pull request becomes stale # Number of days of inactivity before a pull request becomes stale
daysUntilStale: 7 daysUntilStale: 30
# Number of days of inactivity before a stale pull request is closed # Number of days of inactivity before a stale pull request is closed
daysUntilClose: 7 daysUntilClose: 7

7
.gitignore vendored
View File

@@ -1,7 +1,5 @@
/docs/html/ /book/html/
/docs/src/tests.ok /book/src/tests.ok
/docs/src/cli/usage.md
/docs/src/.gitbook/assets/*.svg
/farf/ /farf/
/solana-release/ /solana-release/
/solana-release.tar.bz2 /solana-release.tar.bz2
@@ -17,7 +15,6 @@
# log files # log files
*.log *.log
log-*.txt log-*.txt
log-*/
# intellij files # intellij files
/.idea/ /.idea/

View File

@@ -1,40 +1,9 @@
# Validate your changes with: # Validate your changes with:
# #
# $ curl -F 'data=@.mergify.yml' https://gh.mergify.io/validate/ # $ curl -F 'data=@.mergify.yml' https://gh.mergify.io/validate
# #
# https://doc.mergify.io/ # https://doc.mergify.io/
pull_request_rules: pull_request_rules:
- name: automatic merge (squash) on CI success
conditions:
- status-success=buildkite/solana
#- status-success=Travis CI - Pull Request
- status-success=ci-gate
- label=automerge
- author≠@dont-squash-my-commits
actions:
merge:
method: squash
# Join the dont-squash-my-commits group if you won't like your commits squashed
- name: automatic merge (rebase) on CI success
conditions:
- status-success=buildkite/solana
#- status-success=Travis CI - Pull Request
- status-success=ci-gate
- label=automerge
- author=@dont-squash-my-commits
actions:
merge:
method: rebase
- name: remove automerge label on CI failure
conditions:
- label=automerge
- "#status-failure!=0"
actions:
label:
remove:
- automerge
comment:
message: automerge label removed due to a CI failure
- name: remove outdated reviews - name: remove outdated reviews
conditions: conditions:
- base=master - base=master
@@ -50,30 +19,59 @@ pull_request_rules:
label: label:
add: add:
- automerge - automerge
- name: v1.0 backport - name: v0.16 backport
conditions: conditions:
- base=master - base=master
- label=v1.0 - label=v0.16
actions: actions:
backport: backport:
ignore_conflicts: true
branches: branches:
- v1.0 - v0.16
- name: v1.1 backport - name: v0.17 backport
conditions: conditions:
- base=master - base=master
- label=v1.1 - label=v0.17
actions: actions:
backport: backport:
ignore_conflicts: true
branches: branches:
- v1.1 - v0.17
- name: v1.2 backport - name: v0.18 backport
conditions: conditions:
- base=master - base=master
- label=v1.2 - label=v0.18
actions: actions:
backport: backport:
ignore_conflicts: true
branches: branches:
- v1.2 - v0.18
- name: v0.19 backport
conditions:
- base=master
- label=v0.19
actions:
backport:
branches:
- v0.19
- name: v0.20 backport
conditions:
- base=master
- label=v0.20
actions:
backport:
branches:
- v0.20
- name: v0.21 backport
conditions:
- base=master
- label=v0.21
actions:
backport:
branches:
- v0.21
- name: v0.22 backport
conditions:
- base=master
- label=v0.22
actions:
backport:
branches:
- v0.22

View File

@@ -1,13 +1,13 @@
os: os:
- osx - osx
- windows
language: rust language: rust
rust: rust:
- stable - 1.37.0
install: install:
- source ci/rust-version.sh - source ci/rust-version.sh
- test $rust_stable = $TRAVIS_RUST_VERSION # Update .travis.yml rust version above when this fails
script: script:
- source ci/env.sh - source ci/env.sh
@@ -16,9 +16,7 @@ script:
branches: branches:
only: only:
- master - master
- /^v\d+\.\d+/ - /^v\d+\.\d+$/
if: type IN (api, cron) OR tag IS present
notifications: notifications:
slack: slack:

View File

@@ -1,41 +1,23 @@
# Solana Coding Guidelines Solana Coding Guidelines
===
The goal of these guidelines is to improve developer productivity by allowing The goal of these guidelines is to improve developer productivity by allowing developers to
developers to jump into any file in the codebase and not need to adapt to jump any file in the codebase and not need to adapt to inconsistencies in how the code is
inconsistencies in how the code is written. The codebase should appear as if it written. The codebase should appear as if it had been authored by a single developer. If you
had been authored by a single developer. If you don't agree with a convention, don't agree with a convention, submit a PR patching this document and let's discuss! Once
submit a PR patching this document and let's discuss! Once the PR is accepted, the PR is accepted, *all* code should be updated as soon as possible to reflect the new
*all* code should be updated as soon as possible to reflect the new
conventions. conventions.
## Pull Requests Pull Requests
---
Small, frequent PRs are much preferred to large, infrequent ones. A large PR is Small, frequent PRs are much preferred to large, infrequent ones. A large PR is difficult
difficult to review, can block others from making progress, and can quickly get to review, can block others from making progress, and can quickly get its author into
its author into "rebase hell". A large PR oftentimes arises when one change "rebase hell". A large PR oftentimes arises when one change requires another, which requires
requires another, which requires another, and then another. When you notice another, and then another. When you notice those dependencies, put the fix into a commit of
those dependencies, put the fix into a commit of its own, then checkout a new its own, then checkout a new branch, and cherrypick it. Open a PR to start the review
branch, and cherry-pick it. process and then jump back to your original branch to keep making progress. Once the commit
is merged, you can use git-rebase to purge it from your original branch.
```bash
$ git commit -am "Fix foo, needed by bar"
$ git checkout master
$ git checkout -b fix-foo
$ git cherry-pick fix-bar
$ git push --set-upstream origin fix-foo
```
Open a PR to start the review process and then jump back to your original
branch to keep making progress. Consider rebasing to make your fix the first
commit:
```bash
$ git checkout fix-bar
$ git rebase -i master <Move fix-foo to top>
```
Once the commit is merged, rebase the original branch to purge the
cherry-picked commit:
```bash ```bash
$ git pull --rebase upstream master $ git pull --rebase upstream master
@@ -43,137 +25,26 @@ $ git pull --rebase upstream master
### How big is too big? ### How big is too big?
If there are no functional changes, PRs can be very large and that's no If there are no functional changes, PRs can be very large and that's no problem. If,
problem. If, however, your changes are making meaningful changes or additions, however, your changes are making meaningful changes or additions, then about 1,000 lines of
then about 1,000 lines of changes is about the most you should ask a Solana changes is about the most you should ask a Solana maintainer to review.
maintainer to review.
### Should I send small PRs as I develop large, new components? ### Should I send small PRs as I develop large, new components?
Add only code to the codebase that is ready to be deployed. If you are building Add only code to the codebase that is ready to be deployed. If you are building a large
a large library, consider developing it in a separate git repository. When it library, consider developing it in a separate git repository. When it is ready to be
is ready to be integrated, the Solana maintainers will work with you to decide integrated, the Solana maintainers will work with you to decide on a path forward. Smaller
on a path forward. Smaller libraries may be copied in whereas very large ones libraries may be copied in whereas very large ones may be pulled in with a package manager.
may be pulled in with a package manager.
## Getting Pull Requests Merged
There is no single person assigned to watching GitHub PR queue and ushering you
through the process. Typically, you will ask the person that wrote a component
to review changes to it. You can find the author using `git blame` or asking on
Discord. When working to get your PR merged, it's most important to understand
that changing the code is your priority and not necessarily a priority of the
person you need an approval from. Also, while you may interact the most with
the component author, you should aim to be inclusive of others. Providing a
detailed problem description is the most effective means of engaging both the
component author and other potentially interested parties.
Consider opening all PRs as Draft Pull Requests first. Using a draft PR allows
you to kickstart the CI automation, which typically takes between 10 and 30
minutes to execute. Use that time to write a detailed problem description. Once
the description is written and CI succeeds, click the "Ready to Review" button
and add reviewers. Adding reviewers before CI succeeds is a fast path to losing
reviewer engagement. Not only will they be notified and see the PR is not yet
ready for them, they will also be bombarded them with additional notifications
each time you push a commit to get past CI or until they "mute" the PR. Once
muted, you'll need to reach out over some other medium, such as Discord, to
request they have another look. When you use draft PRs, no notifications are
sent when you push commits and edit the PR description. Use draft PRs
liberally. Don't bug the humans until you have gotten past the bots.
### What should be in my PR description?
Reviewing code is hard work and generally involves an attempt to guess the
author's intent at various levels. Please assume reviewer time is scarce and do
what you can to make your PR as consumable as possible. Inspired by techniques
for writing good whitepapers, the guidance here aims to maximize reviewer
engagement.
Assume the reviewer will spend no more than a few seconds reading the PR title.
If it doesn't describe a noteworthy change, don't expect the reviewer to click
to see more.
Next, like the abstract of a whitepaper, the reviewer will spend ~30 seconds
reading the PR problem description. If what is described there doesn't look
more important than competing issues, don't expect the reviewer to read on.
Next, the reviewer will read the proposed changes. At this point, the reviewer
needs to be convinced the proposed changes are a *good* solution to the problem
described above. If the proposed changes, not the code changes, generates
discussion, consider closing the PR and returning with a design proposal
instead.
Finally, once the reviewer understands the problem and agrees with the approach
to solving it, the reviewer will view the code changes. At this point, the
reviewer is simply looking to see if the implementation actually implements
what was proposed and if that implementation is maintainable. When a concise,
readable test for each new code path is present, the reviewer can safely ignore
the details of its implementation. When those tests are missing, expect to
either lose engagement or get a pile of review comments as the reviewer
attempts to consider every ambiguity in your implementation.
### The PR Title
The PR title should contain a brief summary of the change, from the perspective
of the user. Examples of good titles:
* Add rent to accounts
* Fix out-of-memory error in validator
* Clean up `process_message()` in runtime
The conventions here are all the same as a good git commit title:
* First word capitalized and in the imperative mood, not past tense ("add", not
"added")
* No trailing period
* What was done, whom it was done to, and in what context
### The PR Problem Statement
The git repo implements a product with various features. The problem statement
should describe how the product is missing a feature, how a feature is
incomplete, or how the implementation of a feature is somehow undesirable. If
an issue being fixed already describes the problem, go ahead and copy-paste it.
As mentioned above, reviewer time is scarce. Given a queue of PRs to review,
the reviewer may ignore PRs that expect them to click through links to see if
the PR warrants attention.
### The Proposed Changes
Typically the content under the "Proposed changes" section will be a bulleted
list of steps taken to solve the problem. Oftentimes, the list is identical to
the subject lines of the git commits contained in the PR. It's especially
generous (and not expected) to rebase or reword commits such that each change
matches the logical flow in your PR description.
### When will my PR be reviewed? ### When will my PR be reviewed?
PRs are typically reviewed and merged in under 7 days. If your PR has been open PRs are typically reviewed and merged in under 7 days. If your PR has been open for longer,
for longer, it's a strong indicator that the reviewers aren't confident the it's a strong indicator that the reviewers aren't confident the change meets the quality
change meets the quality standards of the codebase. You might consider closing standards of the codebase. You might consider closing it and coming back with smaller PRs
it and coming back with smaller PRs and longer descriptions detailing what and longer descriptions detailing what problem it solves and how it solves it.
problem it solves and how it solves it. Old PRs will be marked stale and then
closed automatically 7 days later.
### How to manage review feedback? Draft Pull Requests
---
After a reviewer provides feedback, you can quickly say "acknowledged, will
fix" using a thumb's up emoji. If you're confident your fix is exactly as
prescribed, add a reply "Fixed in COMMIT\_HASH" and mark the comment as
resolved. If you're not sure, reply "Is this what you had in mind?
COMMIT\_HASH" and if so, the reviewer will reply and mark the conversation as
resolved. Marking conversations as resolved is an excellent way to engage more
reviewers. Leaving conversations open may imply the PR is not yet ready for
additional review.
### When will my PR be re-reviewed?
Recall that once your PR is opened, a notification is sent every time you push
a commit. After a reviewer adds feedback, they won't be checking on the status
of that feedback after every new commit. Instead, directly mention the reviewer
when you feel your PR is ready for another pass.
## Draft Pull Requests
If you want early feedback on your PR, use GitHub's "Draft Pull Request" If you want early feedback on your PR, use GitHub's "Draft Pull Request"
mechanism. Draft PRs are a convenient way to collaborate with the Solana mechanism. Draft PRs are a convenient way to collaborate with the Solana
@@ -181,68 +52,67 @@ maintainers without triggering notifications as you make changes. When you feel
your PR is ready for a broader audience, you can transition your draft PR to a your PR is ready for a broader audience, you can transition your draft PR to a
standard PR with the click of a button. standard PR with the click of a button.
Do not add reviewers to draft PRs. GitHub doesn't automatically clear Do not add reviewers to draft PRs. GitHub doesn't automatically clear approvals
approvals when you click "Ready for Review", so a review that meant "I approve when you click "Ready for Review", so a review that meant "I approve of the
of the direction" suddenly has the appearance of "I approve of these changes." direction" suddenly has the appearance of "I approve of these changes." Instead,
Instead, add a comment that mentions the usernames that you would like a review add a comment that mentions the usernames that you would like a review from. Ask
from. Ask explicitly what you would like feedback on. explicitly what you would like feedback on.
## Rust coding conventions Rust coding conventions
---
* All Rust code is formatted using the latest version of `rustfmt`. Once * All Rust code is formatted using the latest version of `rustfmt`. Once installed, it will be
installed, it will be updated automatically when you update the compiler with updated automatically when you update the compiler with `rustup`.
`rustup`.
* All Rust code is linted with Clippy. If you'd prefer to ignore its advice, do * All Rust code is linted with Clippy. If you'd prefer to ignore its advice, do so explicitly:
so explicitly:
```rust #[allow(clippy::too_many_arguments)] ``` ```rust
#[allow(clippy::too_many_arguments)]
```
Note: Clippy defaults can be overridden in the top-level file `.clippy.toml`. Note: Clippy defaults can be overridden in the top-level file `.clippy.toml`.
* For variable names, when in doubt, spell it out. The mapping from type names * For variable names, when in doubt, spell it out. The mapping from type names to variable names
to variable names is to lowercase the type name, putting an underscore before is to lowercase the type name, putting an underscore before each capital letter. Variable names
each capital letter. Variable names should *not* be abbreviated unless being should *not* be abbreviated unless being used as closure arguments and the brevity improves
used as closure arguments and the brevity improves readability. When a function readability. When a function has multiple instances of the same type, qualify each with a
has multiple instances of the same type, qualify each with a prefix and prefix and underscore (i.e. alice_keypair) or a numeric suffix (i.e. tx0).
underscore (i.e. alice\_keypair) or a numeric suffix (i.e. tx0).
* For function and method names, use `<verb>_<subject>`. For unit tests, that * For function and method names, use `<verb>_<subject>`. For unit tests, that verb should
verb should always be `test` and for benchmarks the verb should always be always be `test` and for benchmarks the verb should always be `bench`. Avoid namespacing
`bench`. Avoid namespacing function names with some arbitrary word. Avoid function names with some arbitrary word. Avoid abbreviating words in function names.
abbreviating words in function names.
* As they say, "When in Rome, do as the Romans do." A good patch should * As they say, "When in Rome, do as the Romans do." A good patch should acknowledge the coding
acknowledge the coding conventions of the code that surrounds it, even in the conventions of the code that surrounds it, even in the case where that code has not yet been
case where that code has not yet been updated to meet the conventions described updated to meet the conventions described here.
here.
## Terminology Terminology
---
Inventing new terms is allowed, but should only be done when the term is widely Inventing new terms is allowed, but should only be done when the term is widely used and
used and understood. Avoid introducing new 3-letter terms, which can be understood. Avoid introducing new 3-letter terms, which can be confused with 3-letter acronyms.
confused with 3-letter acronyms.
[Terms currently in use](docs/src/terminology.md) [Terms currently in use](book/src/terminology.md)
## Design Proposals Design Proposals
---
Solana's architecture is described by docs generated from markdown files in Solana's architecture is described by a book generated from markdown files in
the `docs/src/` directory, maintained by an *editor* (currently @garious). To the `book/src/` directory, maintained by an *editor* (currently @garious). To
add a design proposal, you'll need to include it in the add a design proposal, you'll need to at least propose a change the content
[Accepted Design Proposals](https://docs.solana.com/proposals) under the [Accepted Design
section of the Solana docs. Here's the full process: Proposals](https://docs.solana.com/book/v/master/proposals) chapter.
Here's the full process:
1. Propose a design by creating a PR that adds a markdown document to the 1. Propose a design by creating a PR that adds a markdown document to the
`docs/src/proposals` directory and references it from the [table of directory `book/src/` and references it from the [table of
contents](docs/src/SUMMARY.md). Add any relevant *maintainers* to the PR contents](book/src/SUMMARY.md). Add any relevant *maintainers* to the PR review.
review.
2. The PR being merged indicates your proposed change was accepted and that the 2. The PR being merged indicates your proposed change was accepted and that the
maintainers support your plan of attack. maintainers support your plan of attack.
3. Submit PRs that implement the proposal. When the implementation reveals the 3. Submit PRs that implement the proposal. When the implementation reveals the
need for tweaks to the proposal, be sure to update the proposal and have that need for tweaks to the proposal, be sure to update the proposal and have
change reviewed by the same people as in step 1. that change reviewed by the same people as in step 1.
4. Once the implementation is complete, submit a PR that moves the link from 4. Once the implementation is complete, submit a PR that moves the link from
the Accepted Proposals to the Implemented Proposals section. the Accepted Proposals to the Implemented Proposals section.

6795
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,72 +1,127 @@
[workspace] [workspace]
# The members list excluding the `validator-cuda` crate
default-members = [
"bench-exchange",
"bench-streamer",
"bench-tps",
"banking_bench",
"chacha-sys",
"client",
"core",
"drone",
"validator",
"genesis",
"genesis_programs",
"gossip",
"install",
"keygen",
"kvstore",
"ledger-tool",
"local_cluster",
"logger",
"merkle-tree",
"measure",
"metrics",
"programs/bpf_loader_api",
"programs/bpf_loader_program",
"programs/budget_api",
"programs/budget_program",
"programs/btc_spv_program",
"programs/btc_spv_api",
"programs/btc_spv_bin",
"programs/config_api",
"programs/config_program",
"programs/config_tests",
"programs/exchange_api",
"programs/exchange_program",
"programs/failure_program",
"programs/move_loader_api",
"programs/move_loader_program",
"programs/librapay_api",
"programs/noop_program",
"programs/stake_api",
"programs/stake_program",
"programs/stake_tests",
"programs/storage_api",
"programs/storage_program",
"programs/token_api",
"programs/token_program",
"programs/vote_api",
"programs/vote_program",
"replicator",
"runtime",
"sdk",
"sdk-c",
"upload-perf",
"netutil",
"fixed-buf",
"vote-signer",
"cli",
"rayon-threadlimit",
]
# The default-members list and the `validator-cuda` crate
members = [ members = [
"bench-exchange", "bench-exchange",
"bench-streamer", "bench-streamer",
"bench-tps", "bench-tps",
"accounts-bench", "banking_bench",
"banking-bench",
"chacha",
"chacha-cuda",
"chacha-sys", "chacha-sys",
"cli-config",
"client", "client",
"core", "core",
"dos", "drone",
"download-utils",
"faucet",
"perf",
"validator", "validator",
"genesis", "genesis",
"genesis-programs", "genesis_programs",
"gossip", "gossip",
"install", "install",
"keygen", "keygen",
"ledger", "kvstore",
"ledger-tool", "ledger-tool",
"local-cluster", "local_cluster",
"logger", "logger",
"log-analyzer",
"merkle-tree", "merkle-tree",
"streamer",
"measure", "measure",
"metrics", "metrics",
"net-shaper", "programs/bpf_loader_api",
"programs/bpf_loader", "programs/bpf_loader_program",
"programs/budget", "programs/budget_api",
"programs/btc_spv", "programs/budget_program",
"programs/btc_spv_program",
"programs/btc_spv_api",
"programs/btc_spv_bin", "programs/btc_spv_bin",
"programs/config", "programs/config_api",
"programs/exchange", "programs/config_program",
"programs/failure", "programs/config_tests",
"programs/noop", "programs/exchange_api",
"programs/ownable", "programs/exchange_program",
"programs/stake", "programs/failure_program",
"programs/storage", "programs/move_loader_api",
"programs/vest", "programs/move_loader_program",
"programs/vote", "programs/librapay_api",
"archiver", "programs/noop_program",
"archiver-lib", "programs/stake_api",
"archiver-utils", "programs/stake_program",
"remote-wallet", "programs/stake_tests",
"programs/storage_api",
"programs/storage_program",
"programs/token_api",
"programs/token_program",
"programs/vote_api",
"programs/vote_program",
"replicator",
"runtime", "runtime",
"sdk", "sdk",
"sdk-c", "sdk-c",
"scripts",
"stake-accounts",
"stake-monitor",
"sys-tuner",
"transaction-status",
"upload-perf", "upload-perf",
"net-utils", "netutil",
"version", "fixed-buf",
"vote-signer", "vote-signer",
"cli", "cli",
"rayon-threadlimit", "rayon-threadlimit",
"watchtower", "validator-cuda",
] ]
exclude = [ exclude = [
"programs/bpf", "programs/bpf",
"programs/move_loader",
"programs/librapay",
] ]

View File

@@ -9,7 +9,60 @@ Blockchain Rebuilt for Scale
Solana&trade; is a new blockchain architecture built from the ground up for scale. The architecture supports Solana&trade; is a new blockchain architecture built from the ground up for scale. The architecture supports
up to 710 thousand transactions per second on a gigabit network. up to 710 thousand transactions per second on a gigabit network.
Read all about it at [Solana: Blockchain Rebuilt for Scale](https://docs.solana.com/v/master). Disclaimer
===
All claims, content, designs, algorithms, estimates, roadmaps, specifications, and performance measurements described in this project are done with the author's best effort. It is up to the reader to check and validate their accuracy and truthfulness. Furthermore nothing in this project constitutes a solicitation for investment.
Introduction
===
It's possible for a centralized database to process 710,000 transactions per second on a standard gigabit network if the transactions are, on average, no more than 176 bytes. A centralized database can also replicate itself and maintain high availability without significantly compromising that transaction rate using the distributed system technique known as Optimistic Concurrency Control [\[H.T.Kung, J.T.Robinson (1981)\]](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.65.4735). At Solana, we're demonstrating that these same theoretical limits apply just as well to blockchain on an adversarial network. The key ingredient? Finding a way to share time when nodes can't trust one-another. Once nodes can trust time, suddenly ~40 years of distributed systems research becomes applicable to blockchain!
> Perhaps the most striking difference between algorithms obtained by our method and ones based upon timeout is that using timeout produces a traditional distributed algorithm in which the processes operate asynchronously, while our method produces a globally synchronous one in which every process does the same thing at (approximately) the same time. Our method seems to contradict the whole purpose of distributed processing, which is to permit different processes to operate independently and perform different functions. However, if a distributed system is really a single system, then the processes must be synchronized in some way. Conceptually, the easiest way to synchronize processes is to get them all to do the same thing at the same time. Therefore, our method is used to implement a kernel that performs the necessary synchronization--for example, making sure that two different processes do not try to modify a file at the same time. Processes might spend only a small fraction of their time executing the synchronizing kernel; the rest of the time, they can operate independently--e.g., accessing different files. This is an approach we have advocated even when fault-tolerance is not required. The method's basic simplicity makes it easier to understand the precise properties of a system, which is crucial if one is to know just how fault-tolerant the system is. [\[L.Lamport (1984)\]](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.71.1078)
Furthermore, and much to our surprise, it can be implemented using a mechanism that has existed in Bitcoin since day one. The Bitcoin feature is called nLocktime and it can be used to postdate transactions using block height instead of a timestamp. As a Bitcoin client, you'd use block height instead of a timestamp if you don't trust the network. Block height turns out to be an instance of what's being called a Verifiable Delay Function in cryptography circles. It's a cryptographically secure way to say time has passed. In Solana, we use a far more granular verifiable delay function, a SHA 256 hash chain, to checkpoint the ledger and coordinate consensus. With it, we implement Optimistic Concurrency Control and are now well en route towards that theoretical limit of 710,000 transactions per second.
Architecture
===
Before you jump into the code, review the online book [Solana: Blockchain Rebuilt for Scale](https://docs.solana.com/book/).
(The _latest_ development version of the online book is also [available here](https://docs.solana.com/book/v/master/).)
Release Binaries
===
Official release binaries are available at [Github Releases](https://github.com/solana-labs/solana/releases).
Additionally we provide pre-release binaries for the latest code on the edge and
beta channels. Note that these pre-release binaries may be less stable than an
official release.
### Edge channel
#### Linux (x86_64-unknown-linux-gnu)
* [solana.tar.bz2](http://release.solana.com/edge/solana-release-x86_64-unknown-linux-gnu.tar.bz2)
* [solana-install-init](http://release.solana.com/edge/solana-install-init-x86_64-unknown-linux-gnu) as a stand-alone executable
#### mac OS (x86_64-apple-darwin)
* [solana.tar.bz2](http://release.solana.com/edge/solana-release-x86_64-apple-darwin.tar.bz2)
* [solana-install-init](http://release.solana.com/edge/solana-install-init-x86_64-apple-darwin) as a stand-alone executable
#### Windows (x86_64-pc-windows-msvc)
* [solana.tar.bz2](http://release.solana.com/edge/solana-release-x86_64-pc-windows-msvc.tar.bz2)
* [solana-install-init.exe](http://release.solana.com/edge/solana-install-init-x86_64-pc-windows-msvc.exe) as a stand-alone executable
#### All platforms
* [solana-metrics.tar.bz2](http://release.solana.com.s3.amazonaws.com/edge/solana-metrics.tar.bz2)
### Beta channel
#### Linux (x86_64-unknown-linux-gnu)
* [solana.tar.bz2](http://release.solana.com/beta/solana-release-x86_64-unknown-linux-gnu.tar.bz2)
* [solana-install-init](http://release.solana.com/beta/solana-install-init-x86_64-unknown-linux-gnu) as a stand-alone executable
#### mac OS (x86_64-apple-darwin)
* [solana.tar.bz2](http://release.solana.com/beta/solana-release-x86_64-apple-darwin.tar.bz2)
* [solana-install-init](http://release.solana.com/beta/solana-install-init-x86_64-apple-darwin) as a stand-alone executable
#### Windows (x86_64-pc-windows-msvc)
* [solana.tar.bz2](http://release.solana.com/beta/solana-release-x86_64-pc-windows-msvc.tar.bz2)
* [solana-install-init.exe](http://release.solana.com/beta/solana-install-init-x86_64-pc-windows-msvc.exe) as a stand-alone executable
#### All platforms
* [solana-metrics.tar.bz2](http://release.solana.com.s3.amazonaws.com/beta/solana-metrics.tar.bz2)
Developing Developing
=== ===
@@ -25,7 +78,7 @@ $ source $HOME/.cargo/env
$ rustup component add rustfmt $ rustup component add rustfmt
``` ```
If your rustc version is lower than 1.39.0, please update it: If your rustc version is lower than 1.37.0, please update it:
```bash ```bash
$ rustup update $ rustup update
@@ -34,8 +87,7 @@ $ rustup update
On Linux systems you may need to install libssl-dev, pkg-config, zlib1g-dev, etc. On Ubuntu: On Linux systems you may need to install libssl-dev, pkg-config, zlib1g-dev, etc. On Ubuntu:
```bash ```bash
$ sudo apt-get update $ sudo apt-get install libssl-dev pkg-config zlib1g-dev llvm clang
$ sudo apt-get install libssl-dev libudev-dev pkg-config zlib1g-dev llvm clang
``` ```
Download the source code: Download the source code:
@@ -68,13 +120,16 @@ $ cargo test
Local Testnet Local Testnet
--- ---
Start your own testnet locally, instructions are in the online docs [Solana: Blockchain Rebuild for Scale: Getting Started](https://docs.solana.com/building-from-source). Start your own testnet locally, instructions are in the book [Solana: Blockchain Rebuild for Scale: Getting Started](https://docs.solana.com/book/getting-started).
Remote Testnets Remote Testnets
--- ---
* `testnet` - public stable testnet accessible via devnet.solana.com. Runs 24/7 We maintain several testnets:
* `testnet` - public stable testnet accessible via testnet.solana.com. Runs 24/7
* `testnet-beta` - public beta channel testnet accessible via beta.testnet.solana.com. Runs 24/7
* `testnet-edge` - public edge channel testnet accessible via edge.testnet.solana.com. Runs 24/7
## Deploy process ## Deploy process
@@ -185,8 +240,3 @@ problem is solved by this code?" On the other hand, if a test does fail and you
better way to solve the same problem, a Pull Request with your solution would most certainly be better way to solve the same problem, a Pull Request with your solution would most certainly be
welcome! Likewise, if rewriting a test can better communicate what code it's protecting, please welcome! Likewise, if rewriting a test can better communicate what code it's protecting, please
send us that patch! send us that patch!
Disclaimer
===
All claims, content, designs, algorithms, estimates, roadmaps, specifications, and performance measurements described in this project are done with the author's best effort. It is up to the reader to check and validate their accuracy and truthfulness. Furthermore nothing in this project constitutes a solicitation for investment.

View File

@@ -138,11 +138,30 @@ There are three release channels that map to branches as follows:
### Update documentation ### Update documentation
TODO: Documentation update procedure is WIP as we move to gitbook TODO: Documentation update procedure is WIP as we move to gitbook
Document the new recommended version by updating `docs/src/running-archiver.md` and `docs/src/validator-testnet.md` on the release (beta) branch to point at the `solana-install` for the upcoming release version. Document the new recommended version by updating `book/src/running-replicator.md` and `book/src/validator-testnet.md` on the release (beta) branch to point at the `solana-install` for the upcoming release version.
### Update software on devnet.solana.com #### Publish updated Book
We maintain three copies of the "book" as official documentation:
The testnet running on devnet.solana.com is set to use a fixed release tag 1) "Book" is the documentation for the latest official release. This should get manually updated whenever a new release is made. It is published here:
https://solana-labs.github.io/book/
2) "Book-edge" tracks the tip of the master branch and updates automatically.
https://solana-labs.github.io/book-edge/
3) "Book-beta" tracks the tip of the beta branch and updates automatically.
https://solana-labs.github.io/book-beta/
To manually trigger an update of the "Book", create a new job of the manual-update-book pipeline.
Set the tag of the latest release as the PUBLISH_BOOK_TAG environment variable.
```bash
PUBLISH_BOOK_TAG=v0.16.6
```
https://buildkite.com/solana-labs/manual-update-book
### Update software on testnet.solana.com
The testnet running on testnet.solana.com is set to use a fixed release tag
which is set in the Buildkite testnet-management pipeline. which is set in the Buildkite testnet-management pipeline.
This tag needs to be updated and the testnet restarted after a new release This tag needs to be updated and the testnet restarted after a new release
tag is created. tag is created.
@@ -182,4 +201,4 @@ TESTNET_OP=create-and-start
### Alert the community ### Alert the community
Notify Discord users on #validator-support that a new release for Notify Discord users on #validator-support that a new release for
devnet.solana.com is available testnet.solana.com is available

View File

@@ -1,22 +0,0 @@
[package]
authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-accounts-bench"
version = "1.1.24"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
[dependencies]
log = "0.4.6"
rayon = "1.3.0"
solana-logger = { path = "../logger", version = "1.1.24" }
solana-runtime = { path = "../runtime", version = "1.1.24" }
solana-measure = { path = "../measure", version = "1.1.24" }
solana-sdk = { path = "../sdk", version = "1.1.24" }
rand = "0.7.0"
clap = "2.33.0"
crossbeam-channel = "0.4"
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@@ -1,105 +0,0 @@
use clap::{value_t, App, Arg};
use rayon::prelude::*;
use solana_measure::measure::Measure;
use solana_runtime::{
accounts::{create_test_accounts, update_accounts, Accounts},
accounts_index::Ancestors,
};
use solana_sdk::pubkey::Pubkey;
use std::fs;
use std::path::PathBuf;
fn main() {
solana_logger::setup();
let matches = App::new("crate")
.about("about")
.version("version")
.arg(
Arg::with_name("num_slots")
.long("num_slots")
.takes_value(true)
.value_name("SLOTS")
.help("Number of slots to store to."),
)
.arg(
Arg::with_name("num_accounts")
.long("num_accounts")
.takes_value(true)
.value_name("NUM_ACCOUNTS")
.help("Total number of accounts"),
)
.arg(
Arg::with_name("iterations")
.long("iterations")
.takes_value(true)
.value_name("ITERATIONS")
.help("Number of bench iterations"),
)
.arg(
Arg::with_name("clean")
.long("clean")
.takes_value(false)
.help("Run clean"),
)
.get_matches();
let num_slots = value_t!(matches, "num_slots", usize).unwrap_or(4);
let num_accounts = value_t!(matches, "num_accounts", usize).unwrap_or(10_000);
let iterations = value_t!(matches, "iterations", usize).unwrap_or(20);
let clean = matches.is_present("clean");
println!("clean: {:?}", clean);
let path = PathBuf::from("farf/accounts-bench");
if fs::remove_dir_all(path.clone()).is_err() {
println!("Warning: Couldn't remove {:?}", path);
}
let accounts = Accounts::new(vec![path]);
println!("Creating {} accounts", num_accounts);
let mut create_time = Measure::start("create accounts");
let pubkeys: Vec<_> = (0..num_slots)
.into_par_iter()
.map(|slot| {
let mut pubkeys: Vec<Pubkey> = vec![];
create_test_accounts(
&accounts,
&mut pubkeys,
num_accounts / num_slots,
slot as u64,
);
pubkeys
})
.collect();
let pubkeys: Vec<_> = pubkeys.into_iter().flatten().collect();
create_time.stop();
println!(
"created {} accounts in {} slots {}",
(num_accounts / num_slots) * num_slots,
num_slots,
create_time
);
let mut ancestors: Ancestors = vec![(0, 0)].into_iter().collect();
for i in 1..num_slots {
ancestors.insert(i as u64, i - 1);
accounts.add_root(i as u64);
}
for x in 0..iterations {
if clean {
let mut time = Measure::start("clean");
accounts.accounts_db.clean_accounts();
time.stop();
println!("{}", time);
for slot in 0..num_slots {
update_accounts(&accounts, &pubkeys, ((x + 1) * num_slots + slot) as u64);
accounts.add_root((x * num_slots + slot) as u64);
}
} else {
let mut pubkeys: Vec<Pubkey> = vec![];
let mut time = Measure::start("hash");
let hash = accounts.accounts_db.update_accounts_hash(0, &ancestors);
time.stop();
println!("hash: {} {}", hash, time);
create_test_accounts(&accounts, &mut pubkeys, 1, 0);
}
}
}

View File

@@ -1,43 +0,0 @@
[package]
name = "solana-archiver-lib"
version = "1.1.24"
description = "Solana Archiver Library"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
edition = "2018"
[dependencies]
bincode = "1.2.1"
crossbeam-channel = "0.4"
ed25519-dalek = "=1.0.0-pre.3"
log = "0.4.8"
rand = "0.7.0"
rand_chacha = "0.2.2"
solana-client = { path = "../client", version = "1.1.24" }
solana-storage-program = { path = "../programs/storage", version = "1.1.24" }
thiserror = "1.0"
serde = "1.0.105"
serde_json = "1.0.48"
serde_derive = "1.0.103"
solana-net-utils = { path = "../net-utils", version = "1.1.24" }
solana-chacha = { path = "../chacha", version = "1.1.24" }
solana-chacha-sys = { path = "../chacha-sys", version = "1.1.24" }
solana-ledger = { path = "../ledger", version = "1.1.24" }
solana-logger = { path = "../logger", version = "1.1.24" }
solana-perf = { path = "../perf", version = "1.1.24" }
solana-sdk = { path = "../sdk", version = "1.1.24" }
solana-core = { path = "../core", version = "1.1.24" }
solana-streamer = { path = "../streamer", version = "1.1.24" }
solana-archiver-utils = { path = "../archiver-utils", version = "1.1.24" }
solana-metrics = { path = "../metrics", version = "1.1.24" }
[dev-dependencies]
hex = "0.4.2"
[lib]
name = "solana_archiver_lib"
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@@ -1,11 +0,0 @@
#[macro_use]
extern crate log;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate solana_metrics;
pub mod archiver;
mod result;

View File

@@ -1,47 +0,0 @@
use solana_client::client_error;
use solana_ledger::blockstore;
use solana_sdk::transport;
use std::any::Any;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum ArchiverError {
#[error("IO error")]
IO(#[from] std::io::Error),
#[error("blockstore error")]
BlockstoreError(#[from] blockstore::BlockstoreError),
#[error("crossbeam error")]
CrossbeamSendError(#[from] crossbeam_channel::SendError<u64>),
#[error("send error")]
SendError(#[from] std::sync::mpsc::SendError<u64>),
#[error("join error")]
JoinError(Box<dyn Any + Send + 'static>),
#[error("transport error")]
TransportError(#[from] transport::TransportError),
#[error("client error")]
ClientError(#[from] client_error::ClientError),
#[error("Json parsing error")]
JsonError(#[from] serde_json::error::Error),
#[error("Storage account has no balance")]
EmptyStorageAccountBalance,
#[error("No RPC peers..")]
NoRpcPeers,
#[error("Couldn't download full segment")]
SegmentDownloadError,
}
impl std::convert::From<Box<dyn Any + Send + 'static>> for ArchiverError {
fn from(e: Box<dyn Any + Send + 'static>) -> ArchiverError {
ArchiverError::JoinError(e)
}
}

View File

@@ -1,28 +0,0 @@
[package]
name = "solana-archiver-utils"
version = "1.1.24"
description = "Solana Archiver Utils"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
edition = "2018"
[dependencies]
log = "0.4.8"
rand = "0.7.0"
solana-chacha = { path = "../chacha", version = "1.1.24" }
solana-chacha-sys = { path = "../chacha-sys", version = "1.1.24" }
solana-ledger = { path = "../ledger", version = "1.1.24" }
solana-logger = { path = "../logger", version = "1.1.24" }
solana-perf = { path = "../perf", version = "1.1.24" }
solana-sdk = { path = "../sdk", version = "1.1.24" }
[dev-dependencies]
hex = "0.4.2"
[lib]
name = "solana_archiver_utils"
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@@ -1,120 +0,0 @@
#[macro_use]
extern crate log;
use solana_sdk::hash::{Hash, Hasher};
use std::fs::File;
use std::io::{self, BufReader, ErrorKind, Read, Seek, SeekFrom};
use std::mem::size_of;
use std::path::Path;
pub fn sample_file(in_path: &Path, sample_offsets: &[u64]) -> io::Result<Hash> {
let in_file = File::open(in_path)?;
let metadata = in_file.metadata()?;
let mut buffer_file = BufReader::new(in_file);
let mut hasher = Hasher::default();
let sample_size = size_of::<Hash>();
let sample_size64 = sample_size as u64;
let mut buf = vec![0; sample_size];
let file_len = metadata.len();
if file_len < sample_size64 {
return Err(io::Error::new(ErrorKind::Other, "file too short!"));
}
for offset in sample_offsets {
if *offset > (file_len - sample_size64) / sample_size64 {
return Err(io::Error::new(ErrorKind::Other, "offset too large"));
}
buffer_file.seek(SeekFrom::Start(*offset * sample_size64))?;
trace!("sampling @ {} ", *offset);
match buffer_file.read(&mut buf) {
Ok(size) => {
assert_eq!(size, buf.len());
hasher.hash(&buf);
}
Err(e) => {
warn!("Error sampling file");
return Err(e);
}
}
}
Ok(hasher.result())
}
#[cfg(test)]
mod tests {
use super::*;
use rand::{thread_rng, Rng};
use std::fs::{create_dir_all, remove_file};
use std::io::Write;
use std::path::PathBuf;
extern crate hex;
fn tmp_file_path(name: &str) -> PathBuf {
use std::env;
let out_dir = env::var("FARF_DIR").unwrap_or_else(|_| "farf".to_string());
let mut rand_bits = [0u8; 32];
thread_rng().fill(&mut rand_bits[..]);
let mut path = PathBuf::new();
path.push(out_dir);
path.push("tmp");
create_dir_all(&path).unwrap();
path.push(format!("{}-{:?}", name, hex::encode(rand_bits)));
println!("path: {:?}", path);
path
}
#[test]
fn test_sample_file() {
solana_logger::setup();
let in_path = tmp_file_path("test_sample_file_input.txt");
let num_strings = 4096;
let string = "12foobar";
{
let mut in_file = File::create(&in_path).unwrap();
for _ in 0..num_strings {
in_file.write(string.as_bytes()).unwrap();
}
}
let num_samples = (string.len() * num_strings / size_of::<Hash>()) as u64;
let samples: Vec<_> = (0..num_samples).collect();
let res = sample_file(&in_path, samples.as_slice());
let ref_hash: Hash = Hash::new(&[
173, 251, 182, 165, 10, 54, 33, 150, 133, 226, 106, 150, 99, 192, 179, 1, 230, 144,
151, 126, 18, 191, 54, 67, 249, 140, 230, 160, 56, 30, 170, 52,
]);
let res = res.unwrap();
assert_eq!(res, ref_hash);
// Sample just past the end
assert!(sample_file(&in_path, &[num_samples]).is_err());
remove_file(&in_path).unwrap();
}
#[test]
fn test_sample_file_invalid_offset() {
let in_path = tmp_file_path("test_sample_file_invalid_offset_input.txt");
{
let mut in_file = File::create(&in_path).unwrap();
for _ in 0..4096 {
in_file.write("123456foobar".as_bytes()).unwrap();
}
}
let samples = [0, 200000];
let res = sample_file(&in_path, &samples);
assert!(res.is_err());
remove_file(in_path).unwrap();
}
#[test]
fn test_sample_file_missing_file() {
let in_path = tmp_file_path("test_sample_file_that_doesnt_exist.txt");
let samples = [0, 5];
let res = sample_file(&in_path, &samples);
assert!(res.is_err());
}
}

View File

@@ -1,23 +0,0 @@
[package]
authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-archiver"
version = "1.1.24"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
[dependencies]
clap = "2.33.0"
console = "0.10.0"
solana-clap-utils = { path = "../clap-utils", version = "1.1.24" }
solana-core = { path = "../core", version = "1.1.24" }
solana-logger = { path = "../logger", version = "1.1.24" }
solana-metrics = { path = "../metrics", version = "1.1.24" }
solana-archiver-lib = { path = "../archiver-lib", version = "1.1.24" }
solana-net-utils = { path = "../net-utils", version = "1.1.24" }
solana-sdk = { path = "../sdk", version = "1.1.24" }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@@ -1,131 +0,0 @@
use clap::{crate_description, crate_name, App, Arg};
use console::style;
use solana_archiver_lib::archiver::Archiver;
use solana_clap_utils::{
input_parsers::keypair_of, input_validators::is_keypair_or_ask_keyword,
keypair::SKIP_SEED_PHRASE_VALIDATION_ARG,
};
use solana_core::{
cluster_info::{Node, VALIDATOR_PORT_RANGE},
contact_info::ContactInfo,
};
use solana_sdk::{
commitment_config::CommitmentConfig,
signature::{Keypair, Signer},
};
use std::{
net::{IpAddr, Ipv4Addr, SocketAddr},
path::PathBuf,
sync::Arc,
};
fn main() {
solana_logger::setup();
let matches = App::new(crate_name!())
.about(crate_description!())
.version(solana_clap_utils::version!())
.arg(
Arg::with_name("identity_keypair")
.short("i")
.long("identity")
.value_name("PATH")
.takes_value(true)
.validator(is_keypair_or_ask_keyword)
.help("File containing an identity (keypair)"),
)
.arg(
Arg::with_name("entrypoint")
.short("n")
.long("entrypoint")
.value_name("HOST:PORT")
.takes_value(true)
.required(true)
.validator(solana_net_utils::is_host_port)
.help("Rendezvous with the cluster at this entry point"),
)
.arg(
Arg::with_name("ledger")
.short("l")
.long("ledger")
.value_name("DIR")
.takes_value(true)
.required(true)
.help("use DIR as persistent ledger location"),
)
.arg(
Arg::with_name("storage_keypair")
.short("s")
.long("storage-keypair")
.value_name("PATH")
.takes_value(true)
.validator(is_keypair_or_ask_keyword)
.help("File containing the storage account keypair"),
)
.arg(
Arg::with_name(SKIP_SEED_PHRASE_VALIDATION_ARG.name)
.long(SKIP_SEED_PHRASE_VALIDATION_ARG.long)
.help(SKIP_SEED_PHRASE_VALIDATION_ARG.help),
)
.get_matches();
let ledger_path = PathBuf::from(matches.value_of("ledger").unwrap());
let identity_keypair = keypair_of(&matches, "identity_keypair").unwrap_or_else(Keypair::new);
let storage_keypair = keypair_of(&matches, "storage_keypair").unwrap_or_else(|| {
clap::Error::with_description(
"The `storage-keypair` argument was not found",
clap::ErrorKind::ArgumentNotFound,
)
.exit();
});
let entrypoint_addr = matches
.value_of("entrypoint")
.map(|entrypoint| {
solana_net_utils::parse_host_port(entrypoint)
.expect("failed to parse entrypoint address")
})
.unwrap();
let gossip_addr = {
let ip = solana_net_utils::get_public_ip_addr(&entrypoint_addr).unwrap();
let mut addr = SocketAddr::new(ip, 0);
addr.set_ip(solana_net_utils::get_public_ip_addr(&entrypoint_addr).unwrap());
addr
};
let node = Node::new_archiver_with_external_ip(
&identity_keypair.pubkey(),
&gossip_addr,
VALIDATOR_PORT_RANGE,
IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)),
);
println!(
"{} version {} (branch={}, commit={})",
style(crate_name!()).bold(),
solana_clap_utils::version!(),
option_env!("CI_BRANCH").unwrap_or("unknown"),
option_env!("CI_COMMIT").unwrap_or("unknown")
);
solana_metrics::set_host_id(identity_keypair.pubkey().to_string());
println!(
"replicating the data with identity_keypair={:?} gossip_addr={:?}",
identity_keypair.pubkey(),
gossip_addr
);
let entrypoint_info = ContactInfo::new_gossip_entry_point(&entrypoint_addr);
let archiver = Archiver::new(
&ledger_path,
node,
entrypoint_info,
Arc::new(identity_keypair),
Arc::new(storage_keypair),
CommitmentConfig::recent(),
)
.unwrap();
archiver.join();
}

View File

@@ -1,27 +0,0 @@
[package]
authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-banking-bench"
version = "1.1.24"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
[dependencies]
clap = "2.33.1"
crossbeam-channel = "0.4"
log = "0.4.6"
rand = "0.7.0"
rayon = "1.3.0"
solana-core = { path = "../core", version = "1.1.24" }
solana-streamer = { path = "../streamer", version = "1.1.24" }
solana-perf = { path = "../perf", version = "1.1.24" }
solana-ledger = { path = "../ledger", version = "1.1.24" }
solana-logger = { path = "../logger", version = "1.1.24" }
solana-runtime = { path = "../runtime", version = "1.1.24" }
solana-measure = { path = "../measure", version = "1.1.24" }
solana-sdk = { path = "../sdk", version = "1.1.24" }
solana-version = { path = "../version", version = "1.1.24" }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

19
banking_bench/Cargo.toml Normal file
View File

@@ -0,0 +1,19 @@
[package]
authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-banking-bench"
version = "0.19.0-pre0"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
[dependencies]
log = "0.4.6"
rayon = "1.2.0"
solana-core = { path = "../core", version = "0.19.0-pre0" }
solana-logger = { path = "../logger", version = "0.19.0-pre0" }
solana-runtime = { path = "../runtime", version = "0.19.0-pre0" }
solana-measure = { path = "../measure", version = "0.19.0-pre0" }
solana-sdk = { path = "../sdk", version = "0.19.0-pre0" }
rand = "0.6.5"
crossbeam-channel = "0.3"

View File

@@ -1,38 +1,36 @@
use clap::{crate_description, crate_name, value_t, App, Arg}; #[macro_use]
extern crate solana_core;
extern crate crossbeam_channel;
use crossbeam_channel::unbounded; use crossbeam_channel::unbounded;
use log::*; use log::*;
use rand::{thread_rng, Rng}; use rand::{thread_rng, Rng};
use rayon::prelude::*; use rayon::prelude::*;
use solana_core::{ use solana_core::bank_forks::BankForks;
banking_stage::{create_test_recorder, BankingStage}, use solana_core::banking_stage::{create_test_recorder, BankingStage};
cluster_info::ClusterInfo, use solana_core::blocktree::{get_tmp_ledger_path, Blocktree};
cluster_info::Node, use solana_core::cluster_info::ClusterInfo;
poh_recorder::PohRecorder, use solana_core::cluster_info::Node;
poh_recorder::WorkingBankEntry, use solana_core::genesis_utils::{create_genesis_block, GenesisBlockInfo};
}; use solana_core::packet::to_packets_chunked;
use solana_ledger::{ use solana_core::poh_recorder::PohRecorder;
bank_forks::BankForks, use solana_core::poh_recorder::WorkingBankEntry;
blockstore::Blockstore, use solana_core::service::Service;
genesis_utils::{create_genesis_config, GenesisConfigInfo},
get_tmp_ledger_path,
};
use solana_measure::measure::Measure; use solana_measure::measure::Measure;
use solana_perf::packet::to_packets_chunked;
use solana_runtime::bank::Bank; use solana_runtime::bank::Bank;
use solana_sdk::{ use solana_sdk::hash::Hash;
hash::Hash, use solana_sdk::pubkey::Pubkey;
pubkey::Pubkey, use solana_sdk::signature::Keypair;
signature::Keypair, use solana_sdk::signature::Signature;
signature::Signature, use solana_sdk::system_transaction;
system_transaction, use solana_sdk::timing::{duration_as_us, timestamp};
timing::{duration_as_us, timestamp}, use solana_sdk::transaction::Transaction;
transaction::Transaction, use std::iter;
}; use std::sync::atomic::Ordering;
use std::{ use std::sync::mpsc::Receiver;
sync::{atomic::Ordering, mpsc::Receiver, Arc, Mutex}, use std::sync::{Arc, Mutex, RwLock};
thread::sleep, use std::thread::sleep;
time::{Duration, Instant}, use std::time::{Duration, Instant};
};
fn check_txs( fn check_txs(
receiver: &Arc<Receiver<WorkingBankEntry>>, receiver: &Arc<Receiver<WorkingBankEntry>>,
@@ -43,7 +41,7 @@ fn check_txs(
let now = Instant::now(); let now = Instant::now();
let mut no_bank = false; let mut no_bank = false;
loop { loop {
if let Ok((_bank, (entry, _tick_height))) = receiver.recv_timeout(Duration::from_millis(10)) if let Ok((_bank, (entry, _tick_count))) = receiver.recv_timeout(Duration::from_millis(10))
{ {
total += entry.transactions.len(); total += entry.transactions.len();
} }
@@ -65,22 +63,15 @@ fn check_txs(
no_bank no_bank
} }
fn make_accounts_txs( fn make_accounts_txs(txes: usize, mint_keypair: &Keypair, hash: Hash) -> Vec<Transaction> {
total_num_transactions: usize,
hash: Hash,
same_payer: bool,
) -> Vec<Transaction> {
let to_pubkey = Pubkey::new_rand(); let to_pubkey = Pubkey::new_rand();
let payer_key = Keypair::new(); let dummy = system_transaction::transfer(mint_keypair, &to_pubkey, 1, hash);
let dummy = system_transaction::transfer(&payer_key, &to_pubkey, 1, hash); (0..txes)
(0..total_num_transactions)
.into_par_iter() .into_par_iter()
.map(|_| { .map(|_| {
let mut new = dummy.clone(); let mut new = dummy.clone();
let sig: Vec<u8> = (0..64).map(|_| thread_rng().gen()).collect(); let sig: Vec<u8> = (0..64).map(|_| thread_rng().gen()).collect();
if !same_payer { new.message.account_keys[0] = Pubkey::new_rand();
new.message.account_keys[0] = Pubkey::new_rand();
}
new.message.account_keys[1] = Pubkey::new_rand(); new.message.account_keys[1] = Pubkey::new_rand();
new.signatures = vec![Signature::new(&sig[0..64])]; new.signatures = vec![Signature::new(&sig[0..64])];
new new
@@ -104,150 +95,97 @@ fn bytes_as_usize(bytes: &[u8]) -> usize {
bytes[0] as usize | (bytes[1] as usize) << 8 bytes[0] as usize | (bytes[1] as usize) << 8
} }
#[allow(clippy::cognitive_complexity)]
fn main() { fn main() {
solana_logger::setup(); solana_logger::setup();
let num_threads = BankingStage::num_threads() as usize;
let matches = App::new(crate_name!())
.about(crate_description!())
.version(solana_version::version!())
.arg(
Arg::with_name("num_chunks")
.long("num-chunks")
.takes_value(true)
.value_name("SIZE")
.help("Number of transaction chunks."),
)
.arg(
Arg::with_name("packets_per_chunk")
.long("packets-per-chunk")
.takes_value(true)
.value_name("SIZE")
.help("Packets per chunk"),
)
.arg(
Arg::with_name("skip_sanity")
.long("skip-sanity")
.takes_value(false)
.help("Skip transaction sanity execution"),
)
.arg(
Arg::with_name("same_payer")
.long("same-payer")
.takes_value(false)
.help("Use the same payer for transfers"),
)
.arg(
Arg::with_name("iterations")
.long("iterations")
.takes_value(true)
.help("Number of iterations"),
)
.arg(
Arg::with_name("num_threads")
.long("num-threads")
.takes_value(true)
.help("Number of iterations"),
)
.get_matches();
let num_threads =
value_t!(matches, "num_threads", usize).unwrap_or(BankingStage::num_threads() as usize);
// a multiple of packet chunk duplicates to avoid races // a multiple of packet chunk duplicates to avoid races
let num_chunks = value_t!(matches, "num_chunks", usize).unwrap_or(16); const CHUNKS: usize = 8 * 2;
let packets_per_chunk = value_t!(matches, "packets_per_chunk", usize).unwrap_or(192); const PACKETS_PER_BATCH: usize = 192;
let iterations = value_t!(matches, "iterations", usize).unwrap_or(1000); let txes = PACKETS_PER_BATCH * num_threads * CHUNKS;
let total_num_transactions = num_chunks * num_threads * packets_per_chunk;
let mint_total = 1_000_000_000_000; let mint_total = 1_000_000_000_000;
let GenesisConfigInfo { let GenesisBlockInfo {
genesis_config, genesis_block,
mint_keypair, mint_keypair,
.. ..
} = create_genesis_config(mint_total); } = create_genesis_block(mint_total);
let (verified_sender, verified_receiver) = unbounded(); let (verified_sender, verified_receiver) = unbounded();
let (vote_sender, vote_receiver) = unbounded(); let (vote_sender, vote_receiver) = unbounded();
let bank0 = Bank::new(&genesis_config); let bank0 = Bank::new(&genesis_block);
let mut bank_forks = BankForks::new(0, bank0); let mut bank_forks = BankForks::new(0, bank0);
let mut bank = bank_forks.working_bank(); let mut bank = bank_forks.working_bank();
info!("threads: {} txs: {}", num_threads, total_num_transactions); info!("threads: {} txs: {}", num_threads, txes);
let same_payer = matches.is_present("same_payer"); let mut transactions = make_accounts_txs(txes, &mint_keypair, genesis_block.hash());
let mut transactions =
make_accounts_txs(total_num_transactions, genesis_config.hash(), same_payer);
// fund all the accounts // fund all the accounts
transactions.iter().for_each(|tx| { transactions.iter().for_each(|tx| {
let mut fund = system_transaction::transfer( let fund = system_transaction::transfer(
&mint_keypair, &mint_keypair,
&tx.message.account_keys[0], &tx.message.account_keys[0],
mint_total / total_num_transactions as u64, mint_total / txes as u64,
genesis_config.hash(), genesis_block.hash(),
); );
// Ignore any pesky duplicate signature errors in the case we are using single-payer
let sig: Vec<u8> = (0..64).map(|_| thread_rng().gen()).collect();
fund.signatures = vec![Signature::new(&sig[0..64])];
let x = bank.process_transaction(&fund); let x = bank.process_transaction(&fund);
x.unwrap(); x.unwrap();
}); });
//sanity check, make sure all the transactions can execute sequentially
let skip_sanity = matches.is_present("skip_sanity"); transactions.iter().for_each(|tx| {
if !skip_sanity { let res = bank.process_transaction(&tx);
//sanity check, make sure all the transactions can execute sequentially assert!(res.is_ok(), "sanity test transactions");
transactions.iter().for_each(|tx| { });
let res = bank.process_transaction(&tx); bank.clear_signatures();
assert!(res.is_ok(), "sanity test transactions error: {:?}", res); //sanity check, make sure all the transactions can execute in parallel
}); let res = bank.process_transactions(&transactions);
bank.clear_signatures(); for r in res {
//sanity check, make sure all the transactions can execute in parallel assert!(r.is_ok(), "sanity parallel execution");
let res = bank.process_transactions(&transactions);
for r in res {
assert!(r.is_ok(), "sanity parallel execution error: {:?}", r);
}
bank.clear_signatures();
} }
bank.clear_signatures();
let mut verified: Vec<_> = to_packets_chunked(&transactions.clone(), packets_per_chunk); let mut verified: Vec<_> = to_packets_chunked(&transactions.clone(), PACKETS_PER_BATCH)
.into_iter()
.map(|x| {
let len = x.packets.len();
(x, iter::repeat(1).take(len).collect())
})
.collect();
let ledger_path = get_tmp_ledger_path!(); let ledger_path = get_tmp_ledger_path!();
{ {
let blockstore = Arc::new( let blocktree = Arc::new(
Blockstore::open(&ledger_path).expect("Expected to be able to open database ledger"), Blocktree::open(&ledger_path).expect("Expected to be able to open database ledger"),
); );
let (exit, poh_recorder, poh_service, signal_receiver) = let (exit, poh_recorder, poh_service, signal_receiver) =
create_test_recorder(&bank, &blockstore, None); create_test_recorder(&bank, &blocktree);
let cluster_info = ClusterInfo::new_with_invalid_keypair(Node::new_localhost().info); let cluster_info = ClusterInfo::new_with_invalid_keypair(Node::new_localhost().info);
let cluster_info = Arc::new(cluster_info); let cluster_info = Arc::new(RwLock::new(cluster_info));
let banking_stage = BankingStage::new( let _banking_stage = BankingStage::new(
&cluster_info, &cluster_info,
&poh_recorder, &poh_recorder,
verified_receiver, verified_receiver,
vote_receiver, vote_receiver,
None,
); );
poh_recorder.lock().unwrap().set_bank(&bank); poh_recorder.lock().unwrap().set_bank(&bank);
let chunk_len = verified.len() / num_chunks; let chunk_len = verified.len() / CHUNKS;
let mut start = 0; let mut start = 0;
// This is so that the signal_receiver does not go out of scope after the closure. // This is so that the signal_receiver does not go out of scope after the closure.
// If it is dropped before poh_service, then poh_service will error when // If it is dropped before poh_service, then poh_service will error when
// calling send() on the channel. // calling send() on the channel.
let signal_receiver = Arc::new(signal_receiver); let signal_receiver = Arc::new(signal_receiver);
let mut total_us = 0; let signal_receiver2 = signal_receiver.clone();
let mut tx_total_us = 0; let mut total = 0;
let base_tx_count = bank.transaction_count(); let mut tx_total = 0;
let mut txs_processed = 0; let mut txs_processed = 0;
let mut root = 1; let mut root = 1;
let collector = Pubkey::new_rand(); let collector = Pubkey::new_rand();
const ITERS: usize = 1_000;
let config = Config { let config = Config {
packets_per_batch: packets_per_chunk, packets_per_batch: PACKETS_PER_BATCH,
chunk_len, chunk_len,
num_threads, num_threads,
}; };
let mut total_sent = 0; for _ in 0..ITERS {
for _ in 0..iterations {
let now = Instant::now(); let now = Instant::now();
let mut sent = 0; let mut sent = 0;
@@ -271,7 +209,7 @@ fn main() {
index, index,
); );
for xv in v { for xv in v {
sent += xv.packets.len(); sent += xv.0.packets.len();
} }
verified_sender.send(v.to_vec()).unwrap(); verified_sender.send(v.to_vec()).unwrap();
} }
@@ -288,11 +226,7 @@ fn main() {
sleep(Duration::from_millis(5)); sleep(Duration::from_millis(5));
} }
} }
if check_txs( if check_txs(&signal_receiver2, txes / CHUNKS, &poh_recorder) {
&signal_receiver,
total_num_transactions / num_chunks,
&poh_recorder,
) {
debug!( debug!(
"resetting bank {} tx count: {} txs_proc: {}", "resetting bank {} tx count: {} txs_proc: {}",
bank.slot(), bank.slot(),
@@ -301,7 +235,7 @@ fn main() {
); );
assert!(txs_processed < bank.transaction_count()); assert!(txs_processed < bank.transaction_count());
txs_processed = bank.transaction_count(); txs_processed = bank.transaction_count();
tx_total_us += duration_as_us(&now.elapsed()); tx_total += duration_as_us(&now.elapsed());
let mut poh_time = Measure::start("poh_time"); let mut poh_time = Measure::start("poh_time");
poh_recorder.lock().unwrap().reset( poh_recorder.lock().unwrap().reset(
@@ -323,7 +257,7 @@ fn main() {
poh_recorder.lock().unwrap().set_bank(&bank); poh_recorder.lock().unwrap().set_bank(&bank);
assert!(poh_recorder.lock().unwrap().bank().is_some()); assert!(poh_recorder.lock().unwrap().bank().is_some());
if bank.slot() > 32 { if bank.slot() > 32 {
bank_forks.set_root(root, &None, None); bank_forks.set_root(root, &None);
root += 1; root += 1;
} }
debug!( debug!(
@@ -333,21 +267,20 @@ fn main() {
poh_time.as_us(), poh_time.as_us(),
); );
} else { } else {
tx_total_us += duration_as_us(&now.elapsed()); tx_total += duration_as_us(&now.elapsed());
} }
// This signature clear may not actually clear the signatures // This signature clear may not actually clear the signatures
// in this chunk, but since we rotate between CHUNKS then // in this chunk, but since we rotate between CHUNKS then
// we should clear them by the time we come around again to re-use that chunk. // we should clear them by the time we come around again to re-use that chunk.
bank.clear_signatures(); bank.clear_signatures();
total_us += duration_as_us(&now.elapsed()); total += duration_as_us(&now.elapsed());
debug!( debug!(
"time: {} us checked: {} sent: {}", "time: {} us checked: {} sent: {}",
duration_as_us(&now.elapsed()), duration_as_us(&now.elapsed()),
total_num_transactions / num_chunks, txes / CHUNKS,
sent, sent,
); );
total_sent += sent;
if bank.slot() > 0 && bank.slot() % 16 == 0 { if bank.slot() > 0 && bank.slot() % 16 == 0 {
for tx in transactions.iter_mut() { for tx in transactions.iter_mut() {
@@ -355,35 +288,32 @@ fn main() {
let sig: Vec<u8> = (0..64).map(|_| thread_rng().gen()).collect(); let sig: Vec<u8> = (0..64).map(|_| thread_rng().gen()).collect();
tx.signatures[0] = Signature::new(&sig[0..64]); tx.signatures[0] = Signature::new(&sig[0..64]);
} }
verified = to_packets_chunked(&transactions.clone(), packets_per_chunk); verified = to_packets_chunked(&transactions.clone(), PACKETS_PER_BATCH)
.into_iter()
.map(|x| {
let len = x.packets.len();
(x, iter::repeat(1).take(len).collect())
})
.collect();
} }
start += chunk_len; start += chunk_len;
start %= verified.len(); start %= verified.len();
} }
let txs_processed = bank_forks.working_bank().transaction_count();
debug!("processed: {} base: {}", txs_processed, base_tx_count);
eprintln!( eprintln!(
"{{'name': 'banking_bench_total', 'median': '{:.2}'}}", "{{'name': 'banking_bench_total', 'median': '{}'}}",
(1000.0 * 1000.0 * total_sent as f64) / (total_us as f64), total / ITERS as u64,
); );
eprintln!( eprintln!(
"{{'name': 'banking_bench_tx_total', 'median': '{:.2}'}}", "{{'name': 'banking_bench_tx_total', 'median': '{}'}}",
(1000.0 * 1000.0 * total_sent as f64) / (tx_total_us as f64), tx_total / ITERS as u64,
);
eprintln!(
"{{'name': 'banking_bench_success_tx_total', 'median': '{:.2}'}}",
(1000.0 * 1000.0 * (txs_processed - base_tx_count) as f64) / (total_us as f64),
); );
drop(verified_sender);
drop(vote_sender); drop(vote_sender);
exit.store(true, Ordering::Relaxed); exit.store(true, Ordering::Relaxed);
banking_stage.join().unwrap();
debug!("waited for banking_stage");
poh_service.join().unwrap(); poh_service.join().unwrap();
sleep(Duration::from_secs(1)); sleep(Duration::from_secs(1));
debug!("waited for poh_service"); debug!("waited for poh_service");
} }
let _unused = Blockstore::destroy(&ledger_path); let _unused = Blocktree::destroy(&ledger_path);
} }

View File

@@ -2,36 +2,38 @@
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018" edition = "2018"
name = "solana-bench-exchange" name = "solana-bench-exchange"
version = "1.1.24" version = "0.19.0-pre0"
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0" license = "Apache-2.0"
homepage = "https://solana.com/" homepage = "https://solana.com/"
publish = false publish = false
[dependencies] [dependencies]
bincode = "1.1.4"
bs58 = "0.3.0"
clap = "2.32.0" clap = "2.32.0"
itertools = "0.9.0" env_logger = "0.6.2"
itertools = "0.8.0"
log = "0.4.8" log = "0.4.8"
num-derive = "0.3" num-derive = "0.2"
num-traits = "0.2" num-traits = "0.2"
rand = "0.7.0" rand = "0.6.5"
rayon = "1.3.0" rayon = "1.2.0"
serde_json = "1.0.48" serde = "1.0.101"
serde_yaml = "0.8.11" serde_derive = "1.0.101"
solana-clap-utils = { path = "../clap-utils", version = "1.1.24" } serde_json = "1.0.40"
solana-core = { path = "../core", version = "1.1.24" } serde_yaml = "0.8.9"
solana-genesis = { path = "../genesis", version = "1.1.24" } # solana-runtime = { path = "../solana/runtime"}
solana-client = { path = "../client", version = "1.1.24" } solana-core = { path = "../core", version = "0.19.0-pre0" }
solana-faucet = { path = "../faucet", version = "1.1.24" } solana-genesis = { path = "../genesis", version = "0.19.0-pre0" }
solana-exchange-program = { path = "../programs/exchange", version = "1.1.24" } solana-client = { path = "../client", version = "0.19.0-pre0" }
solana-logger = { path = "../logger", version = "1.1.24" } solana-drone = { path = "../drone", version = "0.19.0-pre0" }
solana-metrics = { path = "../metrics", version = "1.1.24" } solana-exchange-api = { path = "../programs/exchange_api", version = "0.19.0-pre0" }
solana-net-utils = { path = "../net-utils", version = "1.1.24" } solana-exchange-program = { path = "../programs/exchange_program", version = "0.19.0-pre0" }
solana-runtime = { path = "../runtime", version = "1.1.24" } solana-logger = { path = "../logger", version = "0.19.0-pre0" }
solana-sdk = { path = "../sdk", version = "1.1.24" } solana-metrics = { path = "../metrics", version = "0.19.0-pre0" }
solana-netutil = { path = "../netutil", version = "0.19.0-pre0" }
[dev-dependencies] solana-runtime = { path = "../runtime", version = "0.19.0-pre0" }
solana-local-cluster = { path = "../local-cluster", version = "1.1.24" } solana-sdk = { path = "../sdk", version = "0.19.0-pre0" }
untrusted = "0.7.0"
[package.metadata.docs.rs] ws = "0.9.0"
targets = ["x86_64-unknown-linux-gnu"]

View File

@@ -360,7 +360,7 @@ The Matcher would initiate the following last swap:
- Row 1, To: Investor 1 trades 2 A token to 12 B tokens - Row 1, To: Investor 1 trades 2 A token to 12 B tokens
- Row 1, From: Investor 2 trades 2 A token from 12 B tokens - Row 1, From: Investor 2 trades 2 A token from 12 B tokens
- Matcher takes 2 B tokens as profit - Matcher takes 4 B tokens as profit
Table becomes: Table becomes:

View File

@@ -7,36 +7,32 @@ use rand::{thread_rng, Rng};
use rayon::prelude::*; use rayon::prelude::*;
use solana_client::perf_utils::{sample_txs, SampleStats}; use solana_client::perf_utils::{sample_txs, SampleStats};
use solana_core::gen_keys::GenKeys; use solana_core::gen_keys::GenKeys;
use solana_exchange_program::{exchange_instruction, exchange_state::*, id}; use solana_drone::drone::request_airdrop_transaction;
use solana_faucet::faucet::request_airdrop_transaction; use solana_exchange_api::exchange_instruction;
use solana_genesis::Base64Account; use solana_exchange_api::exchange_state::*;
use solana_exchange_api::id;
use solana_genesis::PrimordialAccountDetails;
use solana_metrics::datapoint_info; use solana_metrics::datapoint_info;
use solana_sdk::{ use solana_sdk::client::Client;
client::{Client, SyncClient}, use solana_sdk::client::SyncClient;
commitment_config::CommitmentConfig, use solana_sdk::pubkey::Pubkey;
pubkey::Pubkey, use solana_sdk::signature::{Keypair, KeypairUtil};
signature::{Keypair, Signer}, use solana_sdk::timing::{duration_as_ms, duration_as_s};
timing::{duration_as_ms, duration_as_s}, use solana_sdk::transaction::Transaction;
transaction::Transaction, use solana_sdk::{system_instruction, system_program};
{system_instruction, system_program}, use std::cmp;
}; use std::collections::{HashMap, VecDeque};
use std::{ use std::fs::File;
cmp, use std::io::prelude::*;
collections::{HashMap, VecDeque}, use std::mem;
fs::File, use std::net::SocketAddr;
io::prelude::*, use std::path::Path;
mem, use std::process::exit;
net::SocketAddr, use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
path::Path, use std::sync::mpsc::{channel, Receiver, Sender};
process::exit, use std::sync::{Arc, RwLock};
sync::{ use std::thread::{sleep, Builder};
atomic::{AtomicBool, AtomicUsize, Ordering}, use std::time::{Duration, Instant};
mpsc::{channel, Receiver, Sender},
Arc, RwLock,
},
thread::{sleep, Builder},
time::{Duration, Instant},
};
// TODO Chunk length as specified results in a bunch of failures, divide by 10 helps... // TODO Chunk length as specified results in a bunch of failures, divide by 10 helps...
// Assume 4MB network buffers, and 512 byte packets // Assume 4MB network buffers, and 512 byte packets
@@ -93,7 +89,7 @@ pub fn create_client_accounts_file(
keypairs.iter().for_each(|keypair| { keypairs.iter().for_each(|keypair| {
accounts.insert( accounts.insert(
serde_json::to_string(&keypair.to_bytes().to_vec()).unwrap(), serde_json::to_string(&keypair.to_bytes().to_vec()).unwrap(),
Base64Account { PrimordialAccountDetails {
balance: fund_amount, balance: fund_amount,
executable: false, executable: false,
owner: system_program::id().to_string(), owner: system_program::id().to_string(),
@@ -144,7 +140,8 @@ where
let path = Path::new(&client_ids_and_stake_file); let path = Path::new(&client_ids_and_stake_file);
let file = File::open(path).unwrap(); let file = File::open(path).unwrap();
let accounts: HashMap<String, Base64Account> = serde_yaml::from_reader(file).unwrap(); let accounts: HashMap<String, PrimordialAccountDetails> =
serde_yaml::from_reader(file).unwrap();
accounts accounts
.into_iter() .into_iter()
.map(|(keypair, _)| { .map(|(keypair, _)| {
@@ -178,28 +175,19 @@ where
info!("Generating {:?} account keys", total_keys); info!("Generating {:?} account keys", total_keys);
let mut account_keypairs = generate_keypairs(total_keys); let mut account_keypairs = generate_keypairs(total_keys);
let src_keypairs: Vec<_> = account_keypairs let src_pubkeys: Vec<_> = account_keypairs
.drain(0..accounts_in_groups) .drain(0..accounts_in_groups)
.map(|keypair| keypair)
.collect();
let src_pubkeys: Vec<Pubkey> = src_keypairs
.iter()
.map(|keypair| keypair.pubkey()) .map(|keypair| keypair.pubkey())
.collect(); .collect();
let profit_pubkeys: Vec<_> = account_keypairs
let profit_keypairs: Vec<_> = account_keypairs
.drain(0..accounts_in_groups) .drain(0..accounts_in_groups)
.map(|keypair| keypair)
.collect();
let profit_pubkeys: Vec<Pubkey> = profit_keypairs
.iter()
.map(|keypair| keypair.pubkey()) .map(|keypair| keypair.pubkey())
.collect(); .collect();
info!("Create {:?} source token accounts", src_pubkeys.len()); info!("Create {:?} source token accounts", src_pubkeys.len());
create_token_accounts(client, &trader_signers, &src_keypairs); create_token_accounts(client, &trader_signers, &src_pubkeys);
info!("Create {:?} profit token accounts", profit_pubkeys.len()); info!("Create {:?} profit token accounts", profit_pubkeys.len());
create_token_accounts(client, &swapper_signers, &profit_keypairs); create_token_accounts(client, &swapper_signers, &profit_pubkeys);
// Collect the max transaction rate and total tx count seen (single node only) // Collect the max transaction rate and total tx count seen (single node only)
let sample_stats = Arc::new(RwLock::new(Vec::new())); let sample_stats = Arc::new(RwLock::new(Vec::new()));
@@ -256,7 +244,7 @@ where
trace!("Start trader thread"); trace!("Start trader thread");
let trader_thread = { let trader_thread = {
let exit_signal = exit_signal.clone(); let exit_signal = exit_signal.clone();
let shared_txs = shared_txs.clone();
let client = clients[0].clone(); let client = clients[0].clone();
Builder::new() Builder::new()
.name("solana-exchange-trader".to_string()) .name("solana-exchange-trader".to_string())
@@ -393,10 +381,7 @@ fn swapper<T>(
let mut tries = 0; let mut tries = 0;
let mut trade_index = 0; let mut trade_index = 0;
while client while client
.get_balance_with_commitment( .get_balance(&trade_infos[trade_index].trade_account)
&trade_infos[trade_index].trade_account,
CommitmentConfig::recent(),
)
.unwrap_or(0) .unwrap_or(0)
== 0 == 0
{ {
@@ -450,7 +435,7 @@ fn swapper<T>(
account_group = (account_group + 1) % account_groups as usize; account_group = (account_group + 1) % account_groups as usize;
let (blockhash, _fee_calculator) = client let (blockhash, _fee_calculator) = client
.get_recent_blockhash_with_commitment(CommitmentConfig::recent()) .get_recent_blockhash()
.expect("Failed to get blockhash"); .expect("Failed to get blockhash");
let to_swap_txs: Vec<_> = to_swap let to_swap_txs: Vec<_> = to_swap
.par_iter() .par_iter()
@@ -573,39 +558,27 @@ fn trader<T>(
trade_account: trade.pubkey(), trade_account: trade.pubkey(),
order_info, order_info,
}); });
trades.push((signer, trade, side, src)); trades.push((signer, trade.pubkey(), side, src));
} }
account_group = (account_group + 1) % account_groups as usize; account_group = (account_group + 1) % account_groups as usize;
let (blockhash, _fee_calculator) = client let (blockhash, _fee_calculator) = client
.get_recent_blockhash_with_commitment(CommitmentConfig::recent()) .get_recent_blockhash()
.expect("Failed to get blockhash"); .expect("Failed to get blockhash");
trades.chunks(chunk_size).for_each(|chunk| { trades.chunks(chunk_size).for_each(|chunk| {
let trades_txs: Vec<_> = chunk let trades_txs: Vec<_> = chunk
.par_iter() .par_iter()
.map(|(owner, trade, side, src)| { .map(|(signer, trade, side, src)| {
let owner_pubkey = &owner.pubkey(); let s: &Keypair = &signer;
let trade_pubkey = &trade.pubkey(); let owner = &signer.pubkey();
let space = mem::size_of::<ExchangeState>() as u64; let space = mem::size_of::<ExchangeState>() as u64;
Transaction::new_signed_instructions( Transaction::new_signed_instructions(
&[owner.as_ref(), trade], &[s],
vec![ vec![
system_instruction::create_account( system_instruction::create_account(owner, trade, 1, space, &id()),
owner_pubkey,
trade_pubkey,
1,
space,
&id(),
),
exchange_instruction::trade_request( exchange_instruction::trade_request(
owner_pubkey, owner, trade, *side, pair, tokens, price, src,
trade_pubkey,
*side,
pair,
tokens,
price,
src,
), ),
], ],
blockhash, blockhash,
@@ -661,14 +634,12 @@ fn trader<T>(
} }
} }
fn verify_transaction<T>(sync_client: &T, tx: &Transaction) -> bool fn verify_transfer<T>(sync_client: &T, tx: &Transaction) -> bool
where where
T: SyncClient + ?Sized, T: SyncClient + ?Sized,
{ {
for s in &tx.signatures { for s in &tx.signatures {
if let Ok(Some(r)) = if let Ok(Some(r)) = sync_client.get_signature_status(s) {
sync_client.get_signature_status_with_commitment(s, CommitmentConfig::recent())
{
match r { match r {
Ok(_) => { Ok(_) => {
return true; return true;
@@ -687,21 +658,16 @@ fn verify_funding_transfer<T: SyncClient + ?Sized>(
tx: &Transaction, tx: &Transaction,
amount: u64, amount: u64,
) -> bool { ) -> bool {
if verify_transaction(client, tx) { for a in &tx.message().account_keys[1..] {
for a in &tx.message().account_keys[1..] { if client.get_balance(a).unwrap_or(0) >= amount {
if client return true;
.get_balance_with_commitment(a, CommitmentConfig::recent())
.unwrap_or(0)
>= amount
{
return true;
}
} }
} }
false false
} }
pub fn fund_keys<T: Client>(client: &T, source: &Keypair, dests: &[Arc<Keypair>], lamports: u64) { pub fn fund_keys(client: &dyn Client, source: &Keypair, dests: &[Arc<Keypair>], lamports: u64) {
let total = lamports * (dests.len() as u64 + 1); let total = lamports * (dests.len() as u64 + 1);
let mut funded: Vec<(&Keypair, u64)> = vec![(source, total)]; let mut funded: Vec<(&Keypair, u64)> = vec![(source, total)];
let mut notfunded: Vec<&Arc<Keypair>> = dests.iter().collect(); let mut notfunded: Vec<&Arc<Keypair>> = dests.iter().collect();
@@ -775,9 +741,8 @@ pub fn fund_keys<T: Client>(client: &T, source: &Keypair, dests: &[Arc<Keypair>]
to_fund_txs.len(), to_fund_txs.len(),
); );
let (blockhash, _fee_calculator) = client let (blockhash, _fee_calculator) =
.get_recent_blockhash_with_commitment(CommitmentConfig::recent()) client.get_recent_blockhash().expect("blockhash");
.expect("blockhash");
to_fund_txs.par_iter_mut().for_each(|(k, tx)| { to_fund_txs.par_iter_mut().for_each(|(k, tx)| {
tx.sign(&[*k], blockhash); tx.sign(&[*k], blockhash);
}); });
@@ -814,41 +779,27 @@ pub fn fund_keys<T: Client>(client: &T, source: &Keypair, dests: &[Arc<Keypair>]
}); });
funded.append(&mut new_funded); funded.append(&mut new_funded);
funded.retain(|(k, b)| { funded.retain(|(k, b)| {
client client.get_balance(&k.pubkey()).unwrap_or(0) > lamports && *b > lamports
.get_balance_with_commitment(&k.pubkey(), CommitmentConfig::recent())
.unwrap_or(0)
> lamports
&& *b > lamports
}); });
debug!(" Funded: {} left: {}", funded.len(), notfunded.len()); debug!(" Funded: {} left: {}", funded.len(), notfunded.len());
} }
} }
pub fn create_token_accounts<T: Client>( pub fn create_token_accounts(client: &dyn Client, signers: &[Arc<Keypair>], accounts: &[Pubkey]) {
client: &T, let mut notfunded: Vec<(&Arc<Keypair>, &Pubkey)> = signers.iter().zip(accounts).collect();
signers: &[Arc<Keypair>],
accounts: &[Keypair],
) {
let mut notfunded: Vec<(&Arc<Keypair>, &Keypair)> = signers.iter().zip(accounts).collect();
while !notfunded.is_empty() { while !notfunded.is_empty() {
notfunded.chunks(FUND_CHUNK_LEN).for_each(|chunk| { notfunded.chunks(FUND_CHUNK_LEN).for_each(|chunk| {
let mut to_create_txs: Vec<_> = chunk let mut to_create_txs: Vec<_> = chunk
.par_iter() .par_iter()
.map(|(from_keypair, new_keypair)| { .map(|(signer, new)| {
let owner_pubkey = &from_keypair.pubkey(); let owner_pubkey = &signer.pubkey();
let space = mem::size_of::<ExchangeState>() as u64; let space = mem::size_of::<ExchangeState>() as u64;
let create_ix = system_instruction::create_account( let create_ix =
owner_pubkey, system_instruction::create_account(owner_pubkey, new, 1, space, &id());
&new_keypair.pubkey(), let request_ix = exchange_instruction::account_request(owner_pubkey, new);
1,
space,
&id(),
);
let request_ix =
exchange_instruction::account_request(owner_pubkey, &new_keypair.pubkey());
( (
(from_keypair, new_keypair), signer,
Transaction::new_unsigned_instructions(vec![create_ix, request_ix]), Transaction::new_unsigned_instructions(vec![create_ix, request_ix]),
) )
}) })
@@ -867,13 +818,12 @@ pub fn create_token_accounts<T: Client>(
let mut retries = 0; let mut retries = 0;
while !to_create_txs.is_empty() { while !to_create_txs.is_empty() {
let (blockhash, _fee_calculator) = client let (blockhash, _fee_calculator) = client
.get_recent_blockhash_with_commitment(CommitmentConfig::recent()) .get_recent_blockhash()
.expect("Failed to get blockhash"); .expect("Failed to get blockhash");
to_create_txs to_create_txs.par_iter_mut().for_each(|(k, tx)| {
.par_iter_mut() let kp: &Keypair = k;
.for_each(|((from_keypair, to_keypair), tx)| { tx.sign(&[kp], blockhash);
tx.sign(&[from_keypair.as_ref(), to_keypair], blockhash); });
});
to_create_txs.iter().for_each(|(_, tx)| { to_create_txs.iter().for_each(|(_, tx)| {
client.async_send_transaction(tx.clone()).expect("transfer"); client.async_send_transaction(tx.clone()).expect("transfer");
}); });
@@ -881,11 +831,11 @@ pub fn create_token_accounts<T: Client>(
let mut waits = 0; let mut waits = 0;
while !to_create_txs.is_empty() { while !to_create_txs.is_empty() {
sleep(Duration::from_millis(200)); sleep(Duration::from_millis(200));
to_create_txs.retain(|(_, tx)| !verify_transaction(client, &tx)); to_create_txs.retain(|(_, tx)| !verify_transfer(client, &tx));
if to_create_txs.is_empty() { if to_create_txs.is_empty() {
break; break;
} }
info!( debug!(
" {} transactions outstanding, waits {:?}", " {} transactions outstanding, waits {:?}",
to_create_txs.len(), to_create_txs.len(),
waits waits
@@ -898,7 +848,7 @@ pub fn create_token_accounts<T: Client>(
if !to_create_txs.is_empty() { if !to_create_txs.is_empty() {
retries += 1; retries += 1;
info!(" Retry {:?} {} txes left", retries, to_create_txs.len()); debug!(" Retry {:?}", retries);
if retries >= 20 { if retries >= 20 {
error!( error!(
"create_token_accounts: Too many retries ({}), give up", "create_token_accounts: Too many retries ({}), give up",
@@ -910,13 +860,9 @@ pub fn create_token_accounts<T: Client>(
} }
}); });
let mut new_notfunded: Vec<(&Arc<Keypair>, &Keypair)> = vec![]; let mut new_notfunded: Vec<(&Arc<Keypair>, &Pubkey)> = vec![];
for f in &notfunded { for f in &notfunded {
if client if client.get_balance(&f.1).unwrap_or(0) == 0 {
.get_balance_with_commitment(&f.1.pubkey(), CommitmentConfig::recent())
.unwrap_or(0)
== 0
{
new_notfunded.push(*f) new_notfunded.push(*f)
} }
} }
@@ -972,13 +918,8 @@ fn generate_keypairs(num: u64) -> Vec<Keypair> {
rnd.gen_n_keypairs(num) rnd.gen_n_keypairs(num)
} }
pub fn airdrop_lamports<T: Client>( pub fn airdrop_lamports(client: &dyn Client, drone_addr: &SocketAddr, id: &Keypair, amount: u64) {
client: &T, let balance = client.get_balance(&id.pubkey());
faucet_addr: &SocketAddr,
id: &Keypair,
amount: u64,
) {
let balance = client.get_balance_with_commitment(&id.pubkey(), CommitmentConfig::recent());
let balance = balance.unwrap_or(0); let balance = balance.unwrap_or(0);
if balance >= amount { if balance >= amount {
return; return;
@@ -989,40 +930,33 @@ pub fn airdrop_lamports<T: Client>(
info!( info!(
"Airdropping {:?} lamports from {} for {}", "Airdropping {:?} lamports from {} for {}",
amount_to_drop, amount_to_drop,
faucet_addr, drone_addr,
id.pubkey(), id.pubkey(),
); );
let mut tries = 0; let mut tries = 0;
loop { loop {
let (blockhash, _fee_calculator) = client let (blockhash, _fee_calculator) = client
.get_recent_blockhash_with_commitment(CommitmentConfig::recent()) .get_recent_blockhash()
.expect("Failed to get blockhash"); .expect("Failed to get blockhash");
match request_airdrop_transaction(&faucet_addr, &id.pubkey(), amount_to_drop, blockhash) { match request_airdrop_transaction(&drone_addr, &id.pubkey(), amount_to_drop, blockhash) {
Ok(transaction) => { Ok(transaction) => {
let signature = client.async_send_transaction(transaction).unwrap(); let signature = client.async_send_transaction(transaction).unwrap();
for _ in 0..30 { for _ in 0..30 {
if let Ok(Some(_)) = client.get_signature_status_with_commitment( if let Ok(Some(_)) = client.get_signature_status(&signature) {
&signature,
CommitmentConfig::recent(),
) {
break; break;
} }
sleep(Duration::from_millis(100)); sleep(Duration::from_millis(100));
} }
if client if client.get_balance(&id.pubkey()).unwrap_or(0) >= amount {
.get_balance_with_commitment(&id.pubkey(), CommitmentConfig::recent())
.unwrap_or(0)
>= amount
{
break; break;
} }
} }
Err(err) => { Err(err) => {
panic!( panic!(
"Error requesting airdrop: {:?} to addr: {:?} amount: {}", "Error requesting airdrop: {:?} to addr: {:?} amount: {}",
err, faucet_addr, amount err, drone_addr, amount
); );
} }
}; };

View File

@@ -1,14 +1,14 @@
use clap::{crate_description, crate_name, value_t, App, Arg, ArgMatches}; use clap::{crate_description, crate_name, crate_version, value_t, App, Arg, ArgMatches};
use solana_core::gen_keys::GenKeys; use solana_core::gen_keys::GenKeys;
use solana_faucet::faucet::FAUCET_PORT; use solana_drone::drone::DRONE_PORT;
use solana_sdk::signature::{read_keypair_file, Keypair}; use solana_sdk::signature::{read_keypair, Keypair, KeypairUtil};
use std::net::SocketAddr; use std::net::SocketAddr;
use std::process::exit; use std::process::exit;
use std::time::Duration; use std::time::Duration;
pub struct Config { pub struct Config {
pub entrypoint_addr: SocketAddr, pub entrypoint_addr: SocketAddr,
pub faucet_addr: SocketAddr, pub drone_addr: SocketAddr,
pub identity: Keypair, pub identity: Keypair,
pub threads: usize, pub threads: usize,
pub num_nodes: usize, pub num_nodes: usize,
@@ -27,7 +27,7 @@ impl Default for Config {
fn default() -> Self { fn default() -> Self {
Self { Self {
entrypoint_addr: SocketAddr::from(([127, 0, 0, 1], 8001)), entrypoint_addr: SocketAddr::from(([127, 0, 0, 1], 8001)),
faucet_addr: SocketAddr::from(([127, 0, 0, 1], FAUCET_PORT)), drone_addr: SocketAddr::from(([127, 0, 0, 1], DRONE_PORT)),
identity: Keypair::new(), identity: Keypair::new(),
num_nodes: 1, num_nodes: 1,
threads: 4, threads: 4,
@@ -44,10 +44,10 @@ impl Default for Config {
} }
} }
pub fn build_args<'a, 'b>(version: &'b str) -> App<'a, 'b> { pub fn build_args<'a, 'b>() -> App<'a, 'b> {
App::new(crate_name!()) App::new(crate_name!())
.about(crate_description!()) .about(crate_description!())
.version(version) .version(crate_version!())
.arg( .arg(
Arg::with_name("entrypoint") Arg::with_name("entrypoint")
.short("n") .short("n")
@@ -59,14 +59,14 @@ pub fn build_args<'a, 'b>(version: &'b str) -> App<'a, 'b> {
.help("Cluster entry point; defaults to 127.0.0.1:8001"), .help("Cluster entry point; defaults to 127.0.0.1:8001"),
) )
.arg( .arg(
Arg::with_name("faucet") Arg::with_name("drone")
.short("d") .short("d")
.long("faucet") .long("drone")
.value_name("HOST:PORT") .value_name("HOST:PORT")
.takes_value(true) .takes_value(true)
.required(false) .required(false)
.default_value("127.0.0.1:9900") .default_value("127.0.0.1:9900")
.help("Location of the faucet; defaults to 127.0.0.1:9900"), .help("Location of the drone; defaults to 127.0.0.1:9900"),
) )
.arg( .arg(
Arg::with_name("identity") Arg::with_name("identity")
@@ -166,22 +166,20 @@ pub fn build_args<'a, 'b>(version: &'b str) -> App<'a, 'b> {
pub fn extract_args<'a>(matches: &ArgMatches<'a>) -> Config { pub fn extract_args<'a>(matches: &ArgMatches<'a>) -> Config {
let mut args = Config::default(); let mut args = Config::default();
args.entrypoint_addr = solana_net_utils::parse_host_port( args.entrypoint_addr = solana_netutil::parse_host_port(matches.value_of("entrypoint").unwrap())
matches.value_of("entrypoint").unwrap(),
)
.unwrap_or_else(|e| {
eprintln!("failed to parse entrypoint address: {}", e);
exit(1)
});
args.faucet_addr = solana_net_utils::parse_host_port(matches.value_of("faucet").unwrap())
.unwrap_or_else(|e| { .unwrap_or_else(|e| {
eprintln!("failed to parse faucet address: {}", e); eprintln!("failed to parse entrypoint address: {}", e);
exit(1)
});
args.drone_addr = solana_netutil::parse_host_port(matches.value_of("drone").unwrap())
.unwrap_or_else(|e| {
eprintln!("failed to parse drone address: {}", e);
exit(1) exit(1)
}); });
if matches.is_present("identity") { if matches.is_present("identity") {
args.identity = read_keypair_file(matches.value_of("identity").unwrap()) args.identity = read_keypair(matches.value_of("identity").unwrap())
.expect("can't read client identity"); .expect("can't read client identity");
} else { } else {
args.identity = { args.identity = {

View File

@@ -5,18 +5,18 @@ pub mod order_book;
use crate::bench::{airdrop_lamports, create_client_accounts_file, do_bench_exchange, Config}; use crate::bench::{airdrop_lamports, create_client_accounts_file, do_bench_exchange, Config};
use log::*; use log::*;
use solana_core::gossip_service::{discover_cluster, get_multi_client}; use solana_core::gossip_service::{discover_cluster, get_multi_client};
use solana_sdk::signature::Signer; use solana_sdk::signature::KeypairUtil;
fn main() { fn main() {
solana_logger::setup(); solana_logger::setup();
solana_metrics::set_panic_hook("bench-exchange"); solana_metrics::set_panic_hook("bench-exchange");
let matches = cli::build_args(solana_clap_utils::version!()).get_matches(); let matches = cli::build_args().get_matches();
let cli_config = cli::extract_args(&matches); let cli_config = cli::extract_args(&matches);
let cli::Config { let cli::Config {
entrypoint_addr, entrypoint_addr,
faucet_addr, drone_addr,
identity, identity,
threads, threads,
num_nodes, num_nodes,
@@ -54,7 +54,7 @@ fn main() {
); );
} else { } else {
info!("Connecting to the cluster"); info!("Connecting to the cluster");
let (nodes, _archivers) = let (nodes, _replicators) =
discover_cluster(&entrypoint_addr, num_nodes).unwrap_or_else(|_| { discover_cluster(&entrypoint_addr, num_nodes).unwrap_or_else(|_| {
panic!("Failed to discover nodes"); panic!("Failed to discover nodes");
}); });
@@ -73,7 +73,7 @@ fn main() {
const NUM_SIGNERS: u64 = 2; const NUM_SIGNERS: u64 = 2;
airdrop_lamports( airdrop_lamports(
&client, &client,
&faucet_addr, &drone_addr,
&config.identity, &config.identity,
fund_amount * (accounts_in_groups + 1) as u64 * NUM_SIGNERS, fund_amount * (accounts_in_groups + 1) as u64 * NUM_SIGNERS,
); );

View File

@@ -1,7 +1,7 @@
use itertools::EitherOrBoth::{Both, Left, Right}; use itertools::EitherOrBoth::{Both, Left, Right};
use itertools::Itertools; use itertools::Itertools;
use log::*; use log::*;
use solana_exchange_program::exchange_state::*; use solana_exchange_api::exchange_state::*;
use solana_sdk::pubkey::Pubkey; use solana_sdk::pubkey::Pubkey;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::collections::BinaryHeap; use std::collections::BinaryHeap;

View File

@@ -2,17 +2,13 @@
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018" edition = "2018"
name = "solana-bench-streamer" name = "solana-bench-streamer"
version = "1.1.24" version = "0.19.0-pre0"
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0" license = "Apache-2.0"
homepage = "https://solana.com/" homepage = "https://solana.com/"
[dependencies] [dependencies]
clap = "2.33.0" clap = "2.33.0"
solana-clap-utils = { path = "../clap-utils", version = "1.1.24" } solana-core = { path = "../core", version = "0.19.0-pre0" }
solana-streamer = { path = "../streamer", version = "1.1.24" } solana-logger = { path = "../logger", version = "0.19.0-pre0" }
solana-logger = { path = "../logger", version = "1.1.24" } solana-netutil = { path = "../netutil", version = "0.19.0-pre0" }
solana-net-utils = { path = "../net-utils", version = "1.1.24" }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@@ -1,13 +1,15 @@
use clap::{crate_description, crate_name, App, Arg}; use clap::{crate_description, crate_name, crate_version, App, Arg};
use solana_streamer::packet::{Packet, Packets, PacketsRecycler, PACKET_DATA_SIZE}; use solana_core::packet::PacketsRecycler;
use solana_streamer::streamer::{receiver, PacketReceiver}; use solana_core::packet::{Packet, Packets, BLOB_SIZE, PACKET_DATA_SIZE};
use solana_core::result::Result;
use solana_core::streamer::{receiver, PacketReceiver};
use std::cmp::max; use std::cmp::max;
use std::net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket}; use std::net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket};
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::mpsc::channel; use std::sync::mpsc::channel;
use std::sync::Arc; use std::sync::Arc;
use std::thread::sleep; use std::thread::sleep;
use std::thread::{spawn, JoinHandle, Result}; use std::thread::{spawn, JoinHandle};
use std::time::Duration; use std::time::Duration;
use std::time::SystemTime; use std::time::SystemTime;
@@ -27,7 +29,7 @@ fn producer(addr: &SocketAddr, exit: Arc<AtomicBool>) -> JoinHandle<()> {
let mut num = 0; let mut num = 0;
for p in &msgs.packets { for p in &msgs.packets {
let a = p.meta.addr(); let a = p.meta.addr();
assert!(p.meta.size < PACKET_DATA_SIZE); assert!(p.meta.size < BLOB_SIZE);
send.send_to(&p.data[..p.meta.size], &a).unwrap(); send.send_to(&p.data[..p.meta.size], &a).unwrap();
num += 1; num += 1;
} }
@@ -52,7 +54,7 @@ fn main() -> Result<()> {
let matches = App::new(crate_name!()) let matches = App::new(crate_name!())
.about(crate_description!()) .about(crate_description!())
.version(solana_clap_utils::version!()) .version(crate_version!())
.arg( .arg(
Arg::with_name("num-recv-sockets") Arg::with_name("num-recv-sockets")
.long("num-recv-sockets") .long("num-recv-sockets")
@@ -67,8 +69,7 @@ fn main() -> Result<()> {
} }
let mut port = 0; let mut port = 0;
let ip_addr = IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)); let mut addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0);
let mut addr = SocketAddr::new(ip_addr, 0);
let exit = Arc::new(AtomicBool::new(false)); let exit = Arc::new(AtomicBool::new(false));
@@ -76,7 +77,7 @@ fn main() -> Result<()> {
let mut read_threads = Vec::new(); let mut read_threads = Vec::new();
let recycler = PacketsRecycler::default(); let recycler = PacketsRecycler::default();
for _ in 0..num_sockets { for _ in 0..num_sockets {
let read = solana_net_utils::bind_to(ip_addr, port, false).unwrap(); let read = solana_netutil::bind_to(port, false).unwrap();
read.set_read_timeout(Some(Duration::new(1, 0))).unwrap(); read.set_read_timeout(Some(Duration::new(1, 0))).unwrap();
addr = read.local_addr().unwrap(); addr = read.local_addr().unwrap();

View File

@@ -2,39 +2,34 @@
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018" edition = "2018"
name = "solana-bench-tps" name = "solana-bench-tps"
version = "1.1.24" version = "0.19.0-pre0"
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0" license = "Apache-2.0"
homepage = "https://solana.com/" homepage = "https://solana.com/"
[dependencies] [dependencies]
bincode = "1.2.1" bincode = "1.1.4"
clap = "2.33.0" clap = "2.33.0"
log = "0.4.8" log = "0.4.8"
rayon = "1.3.0" rayon = "1.2.0"
serde_json = "1.0.48" serde = "1.0.101"
serde_yaml = "0.8.11" serde_derive = "1.0.101"
solana-clap-utils = { path = "../clap-utils", version = "1.1.24" } serde_json = "1.0.40"
solana-core = { path = "../core", version = "1.1.24" } serde_yaml = "0.8.9"
solana-genesis = { path = "../genesis", version = "1.1.24" } solana-core = { path = "../core", version = "0.19.0-pre0" }
solana-client = { path = "../client", version = "1.1.24" } solana-genesis = { path = "../genesis", version = "0.19.0-pre0" }
solana-faucet = { path = "../faucet", version = "1.1.24" } solana-client = { path = "../client", version = "0.19.0-pre0" }
#solana-librapay = { path = "../programs/librapay", version = "1.1.8", optional = true } solana-drone = { path = "../drone", version = "0.19.0-pre0" }
solana-logger = { path = "../logger", version = "1.1.24" } solana-librapay-api = { path = "../programs/librapay_api", version = "0.19.0-pre0" }
solana-metrics = { path = "../metrics", version = "1.1.24" } solana-logger = { path = "../logger", version = "0.19.0-pre0" }
solana-measure = { path = "../measure", version = "1.1.24" } solana-metrics = { path = "../metrics", version = "0.19.0-pre0" }
solana-net-utils = { path = "../net-utils", version = "1.1.24" } solana-measure = { path = "../measure", version = "0.19.0-pre0" }
solana-runtime = { path = "../runtime", version = "1.1.24" } solana-netutil = { path = "../netutil", version = "0.19.0-pre0" }
solana-sdk = { path = "../sdk", version = "1.1.24" } solana-runtime = { path = "../runtime", version = "0.19.0-pre0" }
#solana-move-loader-program = { path = "../programs/move_loader", version = "1.1.8", optional = true } solana-sdk = { path = "../sdk", version = "0.19.0-pre0" }
solana-move-loader-program = { path = "../programs/move_loader_program", version = "0.19.0-pre0" }
solana-move-loader-api = { path = "../programs/move_loader_api", version = "0.19.0-pre0" }
[dev-dependencies] [dev-dependencies]
serial_test = "0.4.0" serial_test = "0.2.0"
serial_test_derive = "0.4.0" serial_test_derive = "0.2.0"
solana-local-cluster = { path = "../local-cluster", version = "1.1.24" }
#[features]
#move = ["solana-librapay", "solana-move-loader-program"]
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

File diff suppressed because it is too large Load Diff

View File

@@ -1,28 +1,29 @@
use clap::{crate_description, crate_name, App, Arg, ArgMatches}; use std::net::SocketAddr;
use solana_faucet::faucet::FAUCET_PORT; use std::process::exit;
use solana_sdk::fee_calculator::FeeRateGovernor; use std::time::Duration;
use solana_sdk::signature::{read_keypair_file, Keypair};
use std::{net::SocketAddr, process::exit, time::Duration};
const NUM_LAMPORTS_PER_ACCOUNT_DEFAULT: u64 = solana_sdk::native_token::LAMPORTS_PER_SOL; use clap::{crate_description, crate_name, crate_version, App, Arg, ArgMatches};
use solana_drone::drone::DRONE_PORT;
use solana_sdk::fee_calculator::FeeCalculator;
use solana_sdk::signature::{read_keypair, Keypair, KeypairUtil};
const NUM_LAMPORTS_PER_ACCOUNT_DEFAULT: u64 = 64 * 1024;
/// Holds the configuration for a single run of the benchmark /// Holds the configuration for a single run of the benchmark
pub struct Config { pub struct Config {
pub entrypoint_addr: SocketAddr, pub entrypoint_addr: SocketAddr,
pub faucet_addr: SocketAddr, pub drone_addr: SocketAddr,
pub id: Keypair, pub id: Keypair,
pub threads: usize, pub threads: usize,
pub num_nodes: usize, pub num_nodes: usize,
pub duration: Duration, pub duration: Duration,
pub tx_count: usize, pub tx_count: usize,
pub keypair_multiplier: usize,
pub thread_batch_sleep_ms: usize, pub thread_batch_sleep_ms: usize,
pub sustained: bool, pub sustained: bool,
pub client_ids_and_stake_file: String, pub client_ids_and_stake_file: String,
pub write_to_client_file: bool, pub write_to_client_file: bool,
pub read_from_client_file: bool, pub read_from_client_file: bool,
pub target_lamports_per_signature: u64, pub target_lamports_per_signature: u64,
pub multi_client: bool,
pub use_move: bool, pub use_move: bool,
pub num_lamports_per_account: u64, pub num_lamports_per_account: u64,
} }
@@ -31,20 +32,18 @@ impl Default for Config {
fn default() -> Config { fn default() -> Config {
Config { Config {
entrypoint_addr: SocketAddr::from(([127, 0, 0, 1], 8001)), entrypoint_addr: SocketAddr::from(([127, 0, 0, 1], 8001)),
faucet_addr: SocketAddr::from(([127, 0, 0, 1], FAUCET_PORT)), drone_addr: SocketAddr::from(([127, 0, 0, 1], DRONE_PORT)),
id: Keypair::new(), id: Keypair::new(),
threads: 4, threads: 4,
num_nodes: 1, num_nodes: 1,
duration: Duration::new(std::u64::MAX, 0), duration: Duration::new(std::u64::MAX, 0),
tx_count: 50_000, tx_count: 500_000,
keypair_multiplier: 8, thread_batch_sleep_ms: 0,
thread_batch_sleep_ms: 1000,
sustained: false, sustained: false,
client_ids_and_stake_file: String::new(), client_ids_and_stake_file: String::new(),
write_to_client_file: false, write_to_client_file: false,
read_from_client_file: false, read_from_client_file: false,
target_lamports_per_signature: FeeRateGovernor::default().target_lamports_per_signature, target_lamports_per_signature: FeeCalculator::default().target_lamports_per_signature,
multi_client: true,
use_move: false, use_move: false,
num_lamports_per_account: NUM_LAMPORTS_PER_ACCOUNT_DEFAULT, num_lamports_per_account: NUM_LAMPORTS_PER_ACCOUNT_DEFAULT,
} }
@@ -52,9 +51,9 @@ impl Default for Config {
} }
/// Defines and builds the CLI args for a run of the benchmark /// Defines and builds the CLI args for a run of the benchmark
pub fn build_args<'a, 'b>(version: &'b str) -> App<'a, 'b> { pub fn build_args<'a, 'b>() -> App<'a, 'b> {
App::new(crate_name!()).about(crate_description!()) App::new(crate_name!()).about(crate_description!())
.version(version) .version(crate_version!())
.arg( .arg(
Arg::with_name("entrypoint") Arg::with_name("entrypoint")
.short("n") .short("n")
@@ -64,12 +63,12 @@ pub fn build_args<'a, 'b>(version: &'b str) -> App<'a, 'b> {
.help("Rendezvous with the cluster at this entry point; defaults to 127.0.0.1:8001"), .help("Rendezvous with the cluster at this entry point; defaults to 127.0.0.1:8001"),
) )
.arg( .arg(
Arg::with_name("faucet") Arg::with_name("drone")
.short("d") .short("d")
.long("faucet") .long("drone")
.value_name("HOST:PORT") .value_name("HOST:PORT")
.takes_value(true) .takes_value(true)
.help("Location of the faucet; defaults to entrypoint:FAUCET_PORT"), .help("Location of the drone; defaults to entrypoint:DRONE_PORT"),
) )
.arg( .arg(
Arg::with_name("identity") Arg::with_name("identity")
@@ -112,11 +111,6 @@ pub fn build_args<'a, 'b>(version: &'b str) -> App<'a, 'b> {
.long("use-move") .long("use-move")
.help("Use Move language transactions to perform transfers."), .help("Use Move language transactions to perform transfers."),
) )
.arg(
Arg::with_name("no-multi-client")
.long("no-multi-client")
.help("Disable multi-client support, only transact with the entrypoint."),
)
.arg( .arg(
Arg::with_name("tx_count") Arg::with_name("tx_count")
.long("tx_count") .long("tx_count")
@@ -124,13 +118,6 @@ pub fn build_args<'a, 'b>(version: &'b str) -> App<'a, 'b> {
.takes_value(true) .takes_value(true)
.help("Number of transactions to send per batch") .help("Number of transactions to send per batch")
) )
.arg(
Arg::with_name("keypair_multiplier")
.long("keypair-multiplier")
.value_name("NUM")
.takes_value(true)
.help("Multiply by transaction count to determine number of keypairs to create")
)
.arg( .arg(
Arg::with_name("thread-batch-sleep-ms") Arg::with_name("thread-batch-sleep-ms")
.short("z") .short("z")
@@ -183,21 +170,21 @@ pub fn extract_args<'a>(matches: &ArgMatches<'a>) -> Config {
let mut args = Config::default(); let mut args = Config::default();
if let Some(addr) = matches.value_of("entrypoint") { if let Some(addr) = matches.value_of("entrypoint") {
args.entrypoint_addr = solana_net_utils::parse_host_port(addr).unwrap_or_else(|e| { args.entrypoint_addr = solana_netutil::parse_host_port(addr).unwrap_or_else(|e| {
eprintln!("failed to parse entrypoint address: {}", e); eprintln!("failed to parse entrypoint address: {}", e);
exit(1) exit(1)
}); });
} }
if let Some(addr) = matches.value_of("faucet") { if let Some(addr) = matches.value_of("drone") {
args.faucet_addr = solana_net_utils::parse_host_port(addr).unwrap_or_else(|e| { args.drone_addr = solana_netutil::parse_host_port(addr).unwrap_or_else(|e| {
eprintln!("failed to parse faucet address: {}", e); eprintln!("failed to parse drone address: {}", e);
exit(1) exit(1)
}); });
} }
if matches.is_present("identity") { if matches.is_present("identity") {
args.id = read_keypair_file(matches.value_of("identity").unwrap()) args.id = read_keypair(matches.value_of("identity").unwrap())
.expect("can't read client identity"); .expect("can't read client identity");
} }
@@ -217,15 +204,7 @@ pub fn extract_args<'a>(matches: &ArgMatches<'a>) -> Config {
} }
if let Some(s) = matches.value_of("tx_count") { if let Some(s) = matches.value_of("tx_count") {
args.tx_count = s.to_string().parse().expect("can't parse tx_count"); args.tx_count = s.to_string().parse().expect("can't parse tx_account");
}
if let Some(s) = matches.value_of("keypair_multiplier") {
args.keypair_multiplier = s
.to_string()
.parse()
.expect("can't parse keypair-multiplier");
assert!(args.keypair_multiplier >= 2);
} }
if let Some(t) = matches.value_of("thread-batch-sleep-ms") { if let Some(t) = matches.value_of("thread-batch-sleep-ms") {
@@ -253,7 +232,6 @@ pub fn extract_args<'a>(matches: &ArgMatches<'a>) -> Config {
} }
args.use_move = matches.is_present("use-move"); args.use_move = matches.is_present("use-move");
args.multi_client = !matches.is_present("no-multi-client");
if let Some(v) = matches.value_of("num_lamports_per_account") { if let Some(v) = matches.value_of("num_lamports_per_account") {
args.num_lamports_per_account = v.to_string().parse().expect("can't parse lamports"); args.num_lamports_per_account = v.to_string().parse().expect("can't parse lamports");

View File

@@ -1,47 +1,45 @@
use log::*;
use solana_bench_tps::bench::{do_bench_tps, generate_and_fund_keypairs, generate_keypairs}; use solana_bench_tps::bench::{do_bench_tps, generate_and_fund_keypairs, generate_keypairs};
use solana_bench_tps::cli; use solana_bench_tps::cli;
use solana_core::gossip_service::{discover_cluster, get_client, get_multi_client}; use solana_core::gossip_service::{discover_cluster, get_multi_client};
use solana_genesis::Base64Account; use solana_genesis::PrimordialAccountDetails;
use solana_sdk::fee_calculator::FeeRateGovernor; use solana_sdk::fee_calculator::FeeCalculator;
use solana_sdk::signature::{Keypair, Signer}; use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::system_program; use solana_sdk::system_program;
use std::{collections::HashMap, fs::File, io::prelude::*, path::Path, process::exit, sync::Arc}; use std::collections::HashMap;
use std::fs::File;
use std::io::prelude::*;
use std::path::Path;
use std::process::exit;
/// Number of signatures for all transactions in ~1 week at ~100K TPS /// Number of signatures for all transactions in ~1 week at ~100K TPS
pub const NUM_SIGNATURES_FOR_TXS: u64 = 100_000 * 60 * 60 * 24 * 7; pub const NUM_SIGNATURES_FOR_TXS: u64 = 100_000 * 60 * 60 * 24 * 7;
fn main() { fn main() {
solana_logger::setup_with_default("solana=info"); solana_logger::setup_with_filter("solana=info");
solana_metrics::set_panic_hook("bench-tps"); solana_metrics::set_panic_hook("bench-tps");
let matches = cli::build_args(solana_clap_utils::version!()).get_matches(); let matches = cli::build_args().get_matches();
let cli_config = cli::extract_args(&matches); let cli_config = cli::extract_args(&matches);
let cli::Config { let cli::Config {
entrypoint_addr, entrypoint_addr,
faucet_addr, drone_addr,
id, id,
num_nodes, num_nodes,
tx_count, tx_count,
keypair_multiplier,
client_ids_and_stake_file, client_ids_and_stake_file,
write_to_client_file, write_to_client_file,
read_from_client_file, read_from_client_file,
target_lamports_per_signature, target_lamports_per_signature,
use_move, use_move,
multi_client,
num_lamports_per_account, num_lamports_per_account,
.. ..
} = &cli_config; } = &cli_config;
let keypair_count = *tx_count * keypair_multiplier;
if *write_to_client_file { if *write_to_client_file {
info!("Generating {} keypairs", keypair_count); let (keypairs, _) = generate_keypairs(&id, *tx_count as u64 * 2);
let (keypairs, _) = generate_keypairs(&id, keypair_count as u64);
let num_accounts = keypairs.len() as u64; let num_accounts = keypairs.len() as u64;
let max_fee = let max_fee = FeeCalculator::new(*target_lamports_per_signature).max_lamports_per_signature;
FeeRateGovernor::new(*target_lamports_per_signature, 0).max_lamports_per_signature;
let num_lamports_per_account = (num_accounts - 1 + NUM_SIGNATURES_FOR_TXS * max_fee) let num_lamports_per_account = (num_accounts - 1 + NUM_SIGNATURES_FOR_TXS * max_fee)
/ num_accounts / num_accounts
+ num_lamports_per_account; + num_lamports_per_account;
@@ -49,7 +47,7 @@ fn main() {
keypairs.iter().for_each(|keypair| { keypairs.iter().for_each(|keypair| {
accounts.insert( accounts.insert(
serde_json::to_string(&keypair.to_bytes().to_vec()).unwrap(), serde_json::to_string(&keypair.to_bytes().to_vec()).unwrap(),
Base64Account { PrimordialAccountDetails {
balance: num_lamports_per_account, balance: num_lamports_per_account,
executable: false, executable: false,
owner: system_program::id().to_string(), owner: system_program::id().to_string(),
@@ -58,7 +56,6 @@ fn main() {
); );
}); });
info!("Writing {}", client_ids_and_stake_file);
let serialized = serde_yaml::to_string(&accounts).unwrap(); let serialized = serde_yaml::to_string(&accounts).unwrap();
let path = Path::new(&client_ids_and_stake_file); let path = Path::new(&client_ids_and_stake_file);
let mut file = File::create(path).unwrap(); let mut file = File::create(path).unwrap();
@@ -66,33 +63,29 @@ fn main() {
return; return;
} }
info!("Connecting to the cluster"); println!("Connecting to the cluster");
let (nodes, _archivers) = let (nodes, _replicators) =
discover_cluster(&entrypoint_addr, *num_nodes).unwrap_or_else(|err| { discover_cluster(&entrypoint_addr, *num_nodes).unwrap_or_else(|err| {
eprintln!("Failed to discover {} nodes: {:?}", num_nodes, err); eprintln!("Failed to discover {} nodes: {:?}", num_nodes, err);
exit(1); exit(1);
}); });
let client = if *multi_client { let (client, num_clients) = get_multi_client(&nodes);
let (client, num_clients) = get_multi_client(&nodes);
if nodes.len() < num_clients {
eprintln!(
"Error: Insufficient nodes discovered. Expecting {} or more",
num_nodes
);
exit(1);
}
Arc::new(client)
} else {
Arc::new(get_client(&nodes))
};
let (keypairs, move_keypairs) = if *read_from_client_file && !use_move { if nodes.len() < num_clients {
eprintln!(
"Error: Insufficient nodes discovered. Expecting {} or more",
num_nodes
);
exit(1);
}
let (keypairs, move_keypairs, keypair_balance) = if *read_from_client_file && !use_move {
let path = Path::new(&client_ids_and_stake_file); let path = Path::new(&client_ids_and_stake_file);
let file = File::open(path).unwrap(); let file = File::open(path).unwrap();
info!("Reading {}", client_ids_and_stake_file); let accounts: HashMap<String, PrimordialAccountDetails> =
let accounts: HashMap<String, Base64Account> = serde_yaml::from_reader(file).unwrap(); serde_yaml::from_reader(file).unwrap();
let mut keypairs = vec![]; let mut keypairs = vec![];
let mut last_balance = 0; let mut last_balance = 0;
@@ -103,27 +96,17 @@ fn main() {
keypairs.push(Keypair::from_bytes(&bytes).unwrap()); keypairs.push(Keypair::from_bytes(&bytes).unwrap());
last_balance = primordial_account.balance; last_balance = primordial_account.balance;
}); });
if keypairs.len() < keypair_count {
eprintln!(
"Expected {} accounts in {}, only received {} (--tx_count mismatch?)",
keypair_count,
client_ids_and_stake_file,
keypairs.len(),
);
exit(1);
}
// Sort keypairs so that do_bench_tps() uses the same subset of accounts for each run. // Sort keypairs so that do_bench_tps() uses the same subset of accounts for each run.
// This prevents the amount of storage needed for bench-tps accounts from creeping up // This prevents the amount of storage needed for bench-tps accounts from creeping up
// across multiple runs. // across multiple runs.
keypairs.sort_by(|x, y| x.pubkey().to_string().cmp(&y.pubkey().to_string())); keypairs.sort_by(|x, y| x.pubkey().to_string().cmp(&y.pubkey().to_string()));
(keypairs, None) (keypairs, None, last_balance)
} else { } else {
generate_and_fund_keypairs( generate_and_fund_keypairs(
client.clone(), &client,
Some(*faucet_addr), Some(*drone_addr),
&id, &id,
keypair_count, *tx_count,
*num_lamports_per_account, *num_lamports_per_account,
*use_move, *use_move,
) )
@@ -133,5 +116,11 @@ fn main() {
}) })
}; };
do_bench_tps(client, cli_config, keypairs, move_keypairs); do_bench_tps(
vec![client],
cli_config,
keypairs,
keypair_balance,
move_keypairs,
);
} }

26
book/README.md Normal file
View File

@@ -0,0 +1,26 @@
Building the Solana book
---
Install the book's dependnecies, build, and test the book:
```bash
$ ./build.sh
```
Run any Rust tests in the markdown:
```bash
$ make test
```
Render markdown as HTML:
```bash
$ make build
```
Render and view the book:
```bash
$ make open
```

15
book/art/consensus.msc Normal file
View File

@@ -0,0 +1,15 @@
msc {
client,leader,verifier_a,verifier_b,verifier_c;
client=>leader [ label = "SUBMIT" ] ;
leader=>client [ label = "CONFIRMED" ] ;
leader=>verifier_a [ label = "CONFIRMED" ] ;
leader=>verifier_b [ label = "CONFIRMED" ] ;
leader=>verifier_c [ label = "CONFIRMED" ] ;
verifier_a=>leader [ label = "VERIFIED" ] ;
verifier_b=>leader [ label = "VERIFIED" ] ;
leader=>client [ label = "FINALIZED" ] ;
leader=>verifier_a [ label = "FINALIZED" ] ;
leader=>verifier_b [ label = "FINALIZED" ] ;
leader=>verifier_c [ label = "FINALIZED" ] ;
}

View File

@@ -24,7 +24,7 @@ msc {
... ; ... ;
Validator abox Validator [label="\nmax\nlockout\n"]; Validator abox Validator [label="\nmax\nlockout\n"];
|||; |||;
Cluster box Cluster [label="credits redeemed (at epoch)"]; StakerX => Cluster [label="StakeState::RedeemCredits()"];
StakerY => Cluster [label="StakeState::RedeemCredits()"] ;
} }

View File

@@ -0,0 +1,18 @@
+------------+
| Bank-Merkle|
+------------+
^ ^
/ \
+-----------------+ +-------------+
| Bank-Diff-Merkle| | Block-Merkle|
+-----------------+ +-------------+
^ ^
/ \
+------+ +--------------------------+
| Hash | | Previous Bank-Diff-Merkle|
+------+ +--------------------------+
^ ^
/ \
+---------------+ +---------------+
| Hash(Account1)| | Hash(Account2)|
+---------------+ +---------------+

22
book/art/tvu.bob Normal file
View File

@@ -0,0 +1,22 @@
.--------.
| Leader |
`--------`
^
|
.------------------------------------|--------------------.
| TVU | |
| | |
| .-------. .------------. .----+---. .---------. |
.------------. | | Blob | | Retransmit | | Replay | | Storage | |
| Upstream +----->| Fetch +-->| Stage +-->| Stage +-->| Stage | |
| Validators | | | Stage | | | | | | | |
`------------` | `-------` `----+-------` `----+---` `---------` |
| ^ | | |
| | | | |
`--------|----------|----------------|--------------------`
| | |
| V v
.+-----------. .------.
| Gossip | | Bank |
| Service | `------`
`------------`

30
book/art/validator.bob Normal file
View File

@@ -0,0 +1,30 @@
.--------------------------------------.
| Validator |
| |
.--------. | .-------------------. |
| |---->| | |
| Client | | | JSON RPC Service | |
| |<----| | |
`----+---` | `-------------------` |
| | ^ |
| | | .----------------. | .------------------.
| | | | Gossip Service |<----------| Validators |
| | | `----------------` | | |
| | | ^ | | |
| | | | | | .------------. |
| | .---+---. .----+---. .-----------. | | | | |
| | | Bank |<-+ Replay | | BlobFetch |<------+ Upstream | |
| | | Forks | | Stage | | Stage | | | | Validators | |
| | `-------` `--------` `--+--------` | | | | |
| | ^ ^ | | | `------------` |
| | | | v | | |
| | | .--+--------. | | |
| | | | Blocktree | | | |
| | | `-----------` | | .------------. |
| | | ^ | | | | |
| | | | | | | Downstream | |
| | .--+--. .-------+---. | | | Validators | |
`-------->| TPU +---->| Broadcast +--------------->| | |
| `-----` | Stage | | | `------------` |
| `-----------` | `------------------`
`--------------------------------------`

View File

@@ -8,5 +8,3 @@ create-missing = false
[output.html] [output.html]
theme = "theme" theme = "theme"
[output.linkcheck]

11
book/build-svg.sh Executable file
View File

@@ -0,0 +1,11 @@
#!/usr/bin/env bash
set -e
cd "$(dirname "$0")"
make -j"$(nproc)" -B svg
if [[ -n $CI ]]; then
# In CI confirm that no svgs need to be built
git diff --exit-code
fi

6
book/build.sh Executable file
View File

@@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -e
cd "$(dirname "$0")"
make -j"$(nproc)" test

View File

@@ -1,6 +1,6 @@
BOB_SRCS=$(wildcard art/*.bob) BOB_SRCS=$(wildcard art/*.bob)
MSC_SRCS=$(wildcard art/*.msc) MSC_SRCS=$(wildcard art/*.msc)
MD_SRCS=$(wildcard src/*.md src/*/*.md) src/cli/usage.md MD_SRCS=$(wildcard src/*.md)
SVG_IMGS=$(BOB_SRCS:art/%.bob=src/.gitbook/assets/%.svg) $(MSC_SRCS:art/%.msc=src/.gitbook/assets/%.svg) SVG_IMGS=$(BOB_SRCS:art/%.bob=src/.gitbook/assets/%.svg) $(MSC_SRCS:art/%.msc=src/.gitbook/assets/%.svg)
@@ -8,7 +8,6 @@ TARGET=html/index.html
TEST_STAMP=src/tests.ok TEST_STAMP=src/tests.ok
all: $(TARGET) all: $(TARGET)
./set-solana-release-tag.sh
svg: $(SVG_IMGS) svg: $(SVG_IMGS)
@@ -28,12 +27,6 @@ src/.gitbook/assets/%.svg: art/%.msc
@mkdir -p $(@D) @mkdir -p $(@D)
mscgen -T svg -i $< -o $@ mscgen -T svg -i $< -o $@
../target/debug/solana:
cd ../cli && cargo build
src/cli/usage.md: build-cli-usage.sh ../target/debug/solana
./$<
src/%.md: %.md src/%.md: %.md
@mkdir -p $(@D) @mkdir -p $(@D)
@cp $< $@ @cp $< $@

View File

@@ -0,0 +1,183 @@
<svg class="bob" font-family="arial" font-size="14" height="304" width="544" xmlns="http://www.w3.org/2000/svg">
<defs>
<marker id="triangle" markerHeight="8" markerWidth="8" orient="auto" refX="4" refY="2" viewBox="0 0 8 4">
<polygon fill="black" points="0,0 0,4 8,2 0,0"/>
</marker>
<marker id="clear_triangle" markerHeight="10" markerWidth="10" orient="auto" refX="1" refY="7" viewBox="0 0 20 14">
<polygon fill="none" points="2,2 2,12 18,7 2,2" stroke="black" stroke-width="2"/>
</marker>
<marker id="circle" markerHeight="5" markerWidth="5" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<circle cx="10" cy="10" fill="black" r="8"/>
</marker>
<marker id="square" markerHeight="5" markerWidth="5" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<rect fill="black" height="20" width="20" x="0" y="0"/>
</marker>
<marker id="open_circle" markerHeight="10" markerWidth="10" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<circle cx="10" cy="10" fill="white" r="4" stroke="black" stroke-width="2"/>
</marker>
<marker id="big_open_circle" markerHeight="20" markerWidth="20" orient="auto" refX="20" refY="20" viewBox="0 0 40 40">
<circle cx="20" cy="20" fill="white" r="6" stroke="black" stroke-width="2"/>
</marker>
</defs>
<style type="text/css">
line,path {
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
line.dashed {
stroke-dasharray: 5;
}
circle.solid {
fill:black;
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
circle.open {
fill:none;
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
tspan.head{
fill: none;
stroke: none;
}
</style>
<rect fill="white" height="304" width="544" x="0" y="0"/>
<g>
<line x1="4" x2="4" y1="8" y2="184"/>
<line x1="4" x2="540" y1="8" y2="8"/>
<line x1="4" x2="540" y1="184" y2="184"/>
<line x1="540" x2="540" y1="8" y2="184"/>
</g>
<g>
<line x1="28" x2="28" y1="232" y2="296"/>
<line x1="28" x2="108" y1="232" y2="232"/>
<line x1="28" x2="196" y1="296" y2="296"/>
<line x1="108" x2="164" y1="232" y2="232"/>
<line x1="164" x2="196" y1="232" y2="232"/>
<line x1="196" x2="196" y1="232" y2="296"/>
</g>
<g>
<line x1="36" x2="36" y1="40" y2="104"/>
<line x1="36" x2="180" y1="40" y2="40"/>
<line x1="36" x2="108" y1="104" y2="104"/>
<line x1="108" x2="108" y1="104" y2="176"/>
<line x1="108" x2="124" y1="104" y2="104"/>
<line x1="124" x2="124" y1="104" y2="136"/>
<line x1="124" x2="180" y1="104" y2="104"/>
<line x1="124" x2="364" y1="136" y2="136"/>
<line x1="180" x2="180" y1="40" y2="56"/>
<line x1="180" x2="180" y1="56" y2="88"/>
<line marker-end="url(#triangle)" x1="180" x2="356" y1="56" y2="56"/>
<line x1="180" x2="180" y1="88" y2="104"/>
<line x1="180" x2="184" y1="88" y2="88"/>
<line x1="364" x2="364" y1="136" y2="152"/>
<line x1="364" x2="364" y1="152" y2="176"/>
<line x1="364" x2="420" y1="152" y2="152"/>
<line x1="420" x2="420" y1="104" y2="152"/>
<line x1="420" x2="436" y1="104" y2="104"/>
<line x1="436" x2="436" y1="104" y2="176"/>
<line x1="436" x2="508" y1="104" y2="104"/>
<line x1="508" x2="508" y1="40" y2="104"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="108" x2="108" y1="192" y2="220"/>
</g>
<g>
<line x1="164" x2="164" y1="152" y2="176"/>
<line x1="164" x2="364" y1="152" y2="152"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="164" x2="164" y1="192" y2="220"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="192" x2="188" y1="88" y2="88"/>
<line x1="192" x2="364" y1="88" y2="88"/>
<line x1="364" x2="364" y1="56" y2="88"/>
<line x1="364" x2="364" y1="88" y2="104"/>
<line x1="364" x2="420" y1="104" y2="104"/>
</g>
<g>
<line x1="348" x2="348" y1="232" y2="296"/>
<line x1="348" x2="364" y1="232" y2="232"/>
<line x1="348" x2="516" y1="296" y2="296"/>
<line x1="364" x2="436" y1="232" y2="232"/>
<line x1="436" x2="516" y1="232" y2="232"/>
<line x1="516" x2="516" y1="232" y2="296"/>
</g>
<g>
<line x1="364" x2="364" y1="40" y2="56"/>
<line x1="364" x2="508" y1="40" y2="40"/>
<line x1="364" x2="360" y1="56" y2="56"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="364" x2="364" y1="192" y2="220"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="436" x2="436" y1="192" y2="220"/>
</g>
<g>
<text x="57" y="268">
Neighborhood
</text>
</g>
<g>
<text x="65" y="76">
Validator
</text>
</g>
<g>
<text x="145" y="76">
1
</text>
</g>
<g>
<text x="161" y="268">
1
</text>
</g>
<g>
<text x="217" y="44">
Neighborhood
</text>
</g>
<g>
<text x="321" y="44">
0
</text>
</g>
<g>
<text x="377" y="268">
Neighborhood
</text>
</g>
<g>
<text x="393" y="76">
Validator
</text>
</g>
<g>
<text x="473" y="76">
2
</text>
</g>
<g>
<text x="481" y="268">
2
</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

@@ -0,0 +1,322 @@
<svg class="bob" font-family="arial" font-size="14" height="400" width="856" xmlns="http://www.w3.org/2000/svg">
<defs>
<marker id="triangle" markerHeight="8" markerWidth="8" orient="auto" refX="4" refY="2" viewBox="0 0 8 4">
<polygon fill="black" points="0,0 0,4 8,2 0,0"/>
</marker>
<marker id="clear_triangle" markerHeight="10" markerWidth="10" orient="auto" refX="1" refY="7" viewBox="0 0 20 14">
<polygon fill="none" points="2,2 2,12 18,7 2,2" stroke="black" stroke-width="2"/>
</marker>
<marker id="circle" markerHeight="5" markerWidth="5" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<circle cx="10" cy="10" fill="black" r="8"/>
</marker>
<marker id="square" markerHeight="5" markerWidth="5" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<rect fill="black" height="20" width="20" x="0" y="0"/>
</marker>
<marker id="open_circle" markerHeight="10" markerWidth="10" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<circle cx="10" cy="10" fill="white" r="4" stroke="black" stroke-width="2"/>
</marker>
<marker id="big_open_circle" markerHeight="20" markerWidth="20" orient="auto" refX="20" refY="20" viewBox="0 0 40 40">
<circle cx="20" cy="20" fill="white" r="6" stroke="black" stroke-width="2"/>
</marker>
</defs>
<style type="text/css">
line,path {
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
line.dashed {
stroke-dasharray: 5;
}
circle.solid {
fill:black;
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
circle.open {
fill:none;
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
tspan.head{
fill: none;
stroke: none;
}
</style>
<rect fill="white" height="400" width="856" x="0" y="0"/>
<g>
<line x1="4" x2="4" y1="8" y2="152"/>
<line x1="4" x2="852" y1="8" y2="8"/>
<line x1="4" x2="852" y1="152" y2="152"/>
<line x1="852" x2="852" y1="8" y2="152"/>
</g>
<g>
<line x1="4" x2="4" y1="248" y2="392"/>
<line x1="4" x2="852" y1="248" y2="248"/>
<line x1="4" x2="852" y1="392" y2="392"/>
<line x1="852" x2="852" y1="248" y2="392"/>
</g>
<g>
<line x1="60" x2="60" y1="56" y2="120"/>
<line x1="60" x2="196" y1="56" y2="56"/>
<line x1="60" x2="84" y1="120" y2="120"/>
<line x1="84" x2="84" y1="120" y2="144"/>
<line x1="84" x2="196" y1="120" y2="120"/>
<line x1="196" x2="196" y1="56" y2="72"/>
<line x1="196" x2="196" y1="72" y2="104"/>
<line marker-end="url(#triangle)" x1="196" x2="252" y1="72" y2="72"/>
<line x1="196" x2="196" y1="104" y2="120"/>
<line x1="196" x2="200" y1="104" y2="104"/>
</g>
<g>
<line x1="60" x2="60" y1="296" y2="360"/>
<line x1="60" x2="84" y1="296" y2="296"/>
<line x1="60" x2="196" y1="360" y2="360"/>
<line x1="84" x2="196" y1="296" y2="296"/>
<line x1="196" x2="196" y1="296" y2="312"/>
<line x1="196" x2="196" y1="312" y2="344"/>
<line marker-end="url(#triangle)" x1="196" x2="252" y1="312" y2="312"/>
<line x1="196" x2="196" y1="344" y2="360"/>
<line x1="196" x2="200" y1="344" y2="344"/>
</g>
<g>
<line x1="84" x2="84" y1="160" y2="240"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="84" x2="84" y1="256" y2="284"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="208" x2="204" y1="104" y2="104"/>
<line x1="208" x2="260" y1="104" y2="104"/>
<line x1="260" x2="260" y1="72" y2="104"/>
<line x1="260" x2="260" y1="104" y2="120"/>
<line x1="260" x2="284" y1="120" y2="120"/>
<line x1="284" x2="284" y1="120" y2="144"/>
<line x1="284" x2="396" y1="120" y2="120"/>
<line x1="396" x2="396" y1="104" y2="120"/>
<line x1="396" x2="400" y1="104" y2="104"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="208" x2="204" y1="344" y2="344"/>
<line x1="208" x2="260" y1="344" y2="344"/>
<line x1="260" x2="260" y1="312" y2="344"/>
<line x1="260" x2="260" y1="344" y2="360"/>
<line x1="260" x2="396" y1="360" y2="360"/>
<line x1="396" x2="396" y1="344" y2="360"/>
<line x1="396" x2="400" y1="344" y2="344"/>
</g>
<g>
<line x1="260" x2="260" y1="56" y2="72"/>
<line x1="260" x2="396" y1="56" y2="56"/>
<line x1="260" x2="256" y1="72" y2="72"/>
<line x1="396" x2="396" y1="56" y2="72"/>
<line x1="396" x2="396" y1="72" y2="104"/>
<line marker-end="url(#triangle)" x1="396" x2="452" y1="72" y2="72"/>
</g>
<g>
<line x1="260" x2="260" y1="296" y2="312"/>
<line x1="260" x2="284" y1="296" y2="296"/>
<line x1="260" x2="256" y1="312" y2="312"/>
<line x1="284" x2="396" y1="296" y2="296"/>
<line x1="396" x2="396" y1="296" y2="312"/>
<line x1="396" x2="396" y1="312" y2="344"/>
<line marker-end="url(#triangle)" x1="396" x2="452" y1="312" y2="312"/>
</g>
<g>
<line x1="284" x2="284" y1="160" y2="240"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="284" x2="284" y1="256" y2="284"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="408" x2="404" y1="104" y2="104"/>
<line x1="408" x2="460" y1="104" y2="104"/>
<line x1="460" x2="460" y1="72" y2="104"/>
<line x1="460" x2="460" y1="104" y2="120"/>
<line x1="460" x2="508" y1="120" y2="120"/>
<line x1="508" x2="508" y1="120" y2="144"/>
<line x1="508" x2="596" y1="120" y2="120"/>
<line x1="596" x2="596" y1="104" y2="120"/>
<line x1="596" x2="600" y1="104" y2="104"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="408" x2="404" y1="344" y2="344"/>
<line x1="408" x2="460" y1="344" y2="344"/>
<line x1="460" x2="460" y1="312" y2="344"/>
<line x1="460" x2="460" y1="344" y2="360"/>
<line x1="460" x2="596" y1="360" y2="360"/>
<line x1="596" x2="596" y1="344" y2="360"/>
<line x1="596" x2="600" y1="344" y2="344"/>
</g>
<g>
<line x1="460" x2="460" y1="56" y2="72"/>
<line x1="460" x2="596" y1="56" y2="56"/>
<line x1="460" x2="456" y1="72" y2="72"/>
<line x1="596" x2="596" y1="56" y2="72"/>
<line x1="596" x2="596" y1="72" y2="104"/>
<line marker-end="url(#triangle)" x1="596" x2="652" y1="72" y2="72"/>
</g>
<g>
<line x1="460" x2="460" y1="296" y2="312"/>
<line x1="460" x2="508" y1="296" y2="296"/>
<line x1="460" x2="456" y1="312" y2="312"/>
<line x1="508" x2="596" y1="296" y2="296"/>
<line x1="596" x2="596" y1="296" y2="312"/>
<line x1="596" x2="596" y1="312" y2="344"/>
<line marker-end="url(#triangle)" x1="596" x2="652" y1="312" y2="312"/>
</g>
<g>
<line x1="508" x2="508" y1="160" y2="240"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="508" x2="508" y1="256" y2="284"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="608" x2="604" y1="104" y2="104"/>
<line x1="608" x2="660" y1="104" y2="104"/>
<line x1="660" x2="660" y1="72" y2="104"/>
<line x1="660" x2="660" y1="104" y2="120"/>
<line x1="660" x2="684" y1="120" y2="120"/>
<line x1="684" x2="684" y1="120" y2="144"/>
<line x1="684" x2="796" y1="120" y2="120"/>
<line x1="796" x2="796" y1="56" y2="120"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="608" x2="604" y1="344" y2="344"/>
<line x1="608" x2="660" y1="344" y2="344"/>
<line x1="660" x2="660" y1="312" y2="344"/>
<line x1="660" x2="660" y1="344" y2="360"/>
<line x1="660" x2="796" y1="360" y2="360"/>
<line x1="796" x2="796" y1="296" y2="360"/>
</g>
<g>
<line x1="660" x2="660" y1="56" y2="72"/>
<line x1="660" x2="796" y1="56" y2="56"/>
<line x1="660" x2="656" y1="72" y2="72"/>
</g>
<g>
<line x1="660" x2="660" y1="296" y2="312"/>
<line x1="660" x2="684" y1="296" y2="296"/>
<line x1="660" x2="656" y1="312" y2="312"/>
<line x1="684" x2="796" y1="296" y2="296"/>
</g>
<g>
<line x1="684" x2="684" y1="160" y2="240"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="684" x2="684" y1="256" y2="284"/>
</g>
<g>
<text x="89" y="92">
Neighbor
</text>
</g>
<g>
<text x="89" y="332">
Neighbor
</text>
</g>
<g>
<text x="161" y="92">
1
</text>
</g>
<g>
<text x="161" y="332">
1
</text>
</g>
<g>
<text x="289" y="92">
Neighbor
</text>
</g>
<g>
<text x="289" y="332">
Neighbor
</text>
</g>
<g>
<text x="353" y="28">
Neighborhood
</text>
</g>
<g>
<text x="353" y="268">
Neighborhood
</text>
</g>
<g>
<text x="361" y="92">
2
</text>
</g>
<g>
<text x="361" y="332">
2
</text>
</g>
<g>
<text x="457" y="28">
Above
</text>
</g>
<g>
<text x="457" y="268">
Below
</text>
</g>
<g>
<text x="489" y="92">
Neighbor
</text>
</g>
<g>
<text x="489" y="332">
Neighbor
</text>
</g>
<g>
<text x="561" y="92">
3
</text>
</g>
<g>
<text x="561" y="332">
3
</text>
</g>
<g>
<text x="689" y="92">
Neighbor
</text>
</g>
<g>
<text x="689" y="332">
Neighbor
</text>
</g>
<g>
<text x="761" y="92">
4
</text>
</g>
<g>
<text x="761" y="332">
4
</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.3 KiB

View File

@@ -0,0 +1,138 @@
<svg class="bob" font-family="arial" font-size="14" height="240" width="544" xmlns="http://www.w3.org/2000/svg">
<defs>
<marker id="triangle" markerHeight="8" markerWidth="8" orient="auto" refX="4" refY="2" viewBox="0 0 8 4">
<polygon fill="black" points="0,0 0,4 8,2 0,0"/>
</marker>
<marker id="clear_triangle" markerHeight="10" markerWidth="10" orient="auto" refX="1" refY="7" viewBox="0 0 20 14">
<polygon fill="none" points="2,2 2,12 18,7 2,2" stroke="black" stroke-width="2"/>
</marker>
<marker id="circle" markerHeight="5" markerWidth="5" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<circle cx="10" cy="10" fill="black" r="8"/>
</marker>
<marker id="square" markerHeight="5" markerWidth="5" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<rect fill="black" height="20" width="20" x="0" y="0"/>
</marker>
<marker id="open_circle" markerHeight="10" markerWidth="10" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<circle cx="10" cy="10" fill="white" r="4" stroke="black" stroke-width="2"/>
</marker>
<marker id="big_open_circle" markerHeight="20" markerWidth="20" orient="auto" refX="20" refY="20" viewBox="0 0 40 40">
<circle cx="20" cy="20" fill="white" r="6" stroke="black" stroke-width="2"/>
</marker>
</defs>
<style type="text/css">
line,path {
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
line.dashed {
stroke-dasharray: 5;
}
circle.solid {
fill:black;
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
circle.open {
fill:none;
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
tspan.head{
fill: none;
stroke: none;
}
</style>
<rect fill="white" height="240" width="544" x="0" y="0"/>
<g>
<line x1="4" x2="4" y1="104" y2="232"/>
<line x1="4" x2="108" y1="104" y2="104"/>
<line x1="4" x2="540" y1="232" y2="232"/>
<line x1="108" x2="436" y1="104" y2="104"/>
<line x1="436" x2="540" y1="104" y2="104"/>
<line x1="540" x2="540" y1="104" y2="232"/>
</g>
<g>
<line x1="36" x2="36" y1="136" y2="200"/>
<line x1="36" x2="180" y1="136" y2="136"/>
<line x1="36" x2="180" y1="200" y2="200"/>
<line x1="180" x2="180" y1="136" y2="152"/>
<line x1="180" x2="180" y1="152" y2="184"/>
<line marker-end="url(#triangle)" x1="180" x2="356" y1="152" y2="152"/>
<line x1="180" x2="180" y1="184" y2="200"/>
<line x1="180" x2="184" y1="184" y2="184"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="108" x2="108" y1="40" y2="92"/>
<line x1="108" x2="212" y1="40" y2="40"/>
<line x1="212" x2="212" y1="8" y2="40"/>
<line x1="212" x2="332" y1="8" y2="8"/>
<line x1="212" x2="212" y1="40" y2="72"/>
<line x1="212" x2="332" y1="72" y2="72"/>
<line x1="332" x2="332" y1="8" y2="40"/>
<line x1="332" x2="332" y1="40" y2="72"/>
<line x1="332" x2="436" y1="40" y2="40"/>
<line marker-end="url(#triangle)" x1="436" x2="436" y1="40" y2="92"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="192" x2="188" y1="184" y2="184"/>
<line x1="192" x2="364" y1="184" y2="184"/>
<line x1="364" x2="364" y1="152" y2="184"/>
<line x1="364" x2="364" y1="184" y2="200"/>
<line x1="364" x2="508" y1="200" y2="200"/>
<line x1="508" x2="508" y1="136" y2="200"/>
</g>
<g>
<line x1="364" x2="364" y1="136" y2="152"/>
<line x1="364" x2="508" y1="136" y2="136"/>
<line x1="364" x2="360" y1="152" y2="152"/>
</g>
<g>
<text x="65" y="172">
Validator
</text>
</g>
<g>
<text x="145" y="172">
1
</text>
</g>
<g>
<text x="217" y="140">
Neighborhood
</text>
</g>
<g>
<text x="249" y="44">
Leader
</text>
</g>
<g>
<text x="321" y="140">
0
</text>
</g>
<g>
<text x="393" y="172">
Validator
</text>
</g>
<g>
<text x="473" y="172">
2
</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@@ -0,0 +1,192 @@
<svg class="bob" font-family="arial" font-size="14" height="288" width="736" xmlns="http://www.w3.org/2000/svg">
<defs>
<marker id="triangle" markerHeight="8" markerWidth="8" orient="auto" refX="4" refY="2" viewBox="0 0 8 4">
<polygon fill="black" points="0,0 0,4 8,2 0,0"/>
</marker>
<marker id="clear_triangle" markerHeight="10" markerWidth="10" orient="auto" refX="1" refY="7" viewBox="0 0 20 14">
<polygon fill="none" points="2,2 2,12 18,7 2,2" stroke="black" stroke-width="2"/>
</marker>
<marker id="circle" markerHeight="5" markerWidth="5" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<circle cx="10" cy="10" fill="black" r="8"/>
</marker>
<marker id="square" markerHeight="5" markerWidth="5" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<rect fill="black" height="20" width="20" x="0" y="0"/>
</marker>
<marker id="open_circle" markerHeight="10" markerWidth="10" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<circle cx="10" cy="10" fill="white" r="4" stroke="black" stroke-width="2"/>
</marker>
<marker id="big_open_circle" markerHeight="20" markerWidth="20" orient="auto" refX="20" refY="20" viewBox="0 0 40 40">
<circle cx="20" cy="20" fill="white" r="6" stroke="black" stroke-width="2"/>
</marker>
</defs>
<style type="text/css">
line,path {
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
line.dashed {
stroke-dasharray: 5;
}
circle.solid {
fill:black;
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
circle.open {
fill:none;
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
tspan.head{
fill: none;
stroke: none;
}
</style>
<rect fill="white" height="288" width="736" x="0" y="0"/>
<g>
<line x1="4" x2="4" y1="216" y2="280"/>
<line x1="4" x2="156" y1="216" y2="216"/>
<line x1="4" x2="172" y1="280" y2="280"/>
<line x1="156" x2="172" y1="216" y2="216"/>
<line x1="172" x2="172" y1="216" y2="280"/>
</g>
<g>
<line x1="124" x2="124" y1="104" y2="168"/>
<line x1="124" x2="204" y1="104" y2="104"/>
<line x1="124" x2="156" y1="168" y2="168"/>
<line marker-end="url(#triangle)" x1="156" x2="156" y1="168" y2="204"/>
<line x1="156" x2="204" y1="168" y2="168"/>
<line x1="204" x2="292" y1="104" y2="104"/>
<line marker-end="url(#triangle)" x1="204" x2="204" y1="168" y2="204"/>
<line x1="204" x2="292" y1="168" y2="168"/>
<line x1="292" x2="292" y1="104" y2="168"/>
</g>
<g>
<line x1="188" x2="188" y1="216" y2="280"/>
<line x1="188" x2="204" y1="216" y2="216"/>
<line x1="188" x2="356" y1="280" y2="280"/>
<line x1="204" x2="356" y1="216" y2="216"/>
<line x1="356" x2="356" y1="216" y2="280"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="204" x2="204" y1="40" y2="92"/>
<line x1="204" x2="276" y1="40" y2="40"/>
<line x1="276" x2="276" y1="8" y2="40"/>
<line x1="276" x2="444" y1="8" y2="8"/>
<line x1="276" x2="276" y1="40" y2="72"/>
<line x1="276" x2="444" y1="72" y2="72"/>
<line x1="444" x2="444" y1="8" y2="40"/>
<line x1="444" x2="444" y1="40" y2="72"/>
<line x1="444" x2="532" y1="40" y2="40"/>
<line marker-end="url(#triangle)" x1="532" x2="532" y1="40" y2="92"/>
</g>
<g>
<line x1="380" x2="380" y1="216" y2="280"/>
<line x1="380" x2="532" y1="216" y2="216"/>
<line x1="380" x2="548" y1="280" y2="280"/>
<line x1="532" x2="548" y1="216" y2="216"/>
<line x1="548" x2="548" y1="216" y2="280"/>
</g>
<g>
<line x1="444" x2="444" y1="104" y2="168"/>
<line x1="444" x2="532" y1="104" y2="104"/>
<line x1="444" x2="532" y1="168" y2="168"/>
<line x1="532" x2="612" y1="104" y2="104"/>
<line marker-end="url(#triangle)" x1="532" x2="532" y1="168" y2="204"/>
<line x1="532" x2="580" y1="168" y2="168"/>
<line marker-end="url(#triangle)" x1="580" x2="580" y1="168" y2="204"/>
<line x1="580" x2="612" y1="168" y2="168"/>
<line x1="612" x2="612" y1="104" y2="168"/>
</g>
<g>
<line x1="564" x2="564" y1="216" y2="280"/>
<line x1="564" x2="580" y1="216" y2="216"/>
<line x1="564" x2="732" y1="280" y2="280"/>
<line x1="580" x2="732" y1="216" y2="216"/>
<line x1="732" x2="732" y1="216" y2="280"/>
</g>
<g>
<text x="33" y="252">
Neighborhood
</text>
</g>
<g>
<text x="137" y="252">
3
</text>
</g>
<g>
<text x="153" y="140">
Neighborhood
</text>
</g>
<g>
<text x="217" y="252">
Neighborhood
</text>
</g>
<g>
<text x="257" y="140">
1
</text>
</g>
<g>
<text x="305" y="44">
Neighborhood
</text>
</g>
<g>
<text x="321" y="252">
4
</text>
</g>
<g>
<text x="409" y="44">
0
</text>
</g>
<g>
<text x="409" y="252">
Neighborhood
</text>
</g>
<g>
<text x="473" y="140">
Neighborhood
</text>
</g>
<g>
<text x="513" y="252">
5
</text>
</g>
<g>
<text x="577" y="140">
2
</text>
</g>
<g>
<text x="593" y="252">
Neighborhood
</text>
</g>
<g>
<text x="697" y="252">
6
</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

@@ -0,0 +1,330 @@
<svg class="bob" font-family="arial" font-size="14" height="208" width="768" xmlns="http://www.w3.org/2000/svg">
<defs>
<marker id="triangle" markerHeight="8" markerWidth="8" orient="auto" refX="4" refY="2" viewBox="0 0 8 4">
<polygon fill="black" points="0,0 0,4 8,2 0,0"/>
</marker>
<marker id="clear_triangle" markerHeight="10" markerWidth="10" orient="auto" refX="1" refY="7" viewBox="0 0 20 14">
<polygon fill="none" points="2,2 2,12 18,7 2,2" stroke="black" stroke-width="2"/>
</marker>
<marker id="circle" markerHeight="5" markerWidth="5" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<circle cx="10" cy="10" fill="black" r="8"/>
</marker>
<marker id="square" markerHeight="5" markerWidth="5" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<rect fill="black" height="20" width="20" x="0" y="0"/>
</marker>
<marker id="open_circle" markerHeight="10" markerWidth="10" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<circle cx="10" cy="10" fill="white" r="4" stroke="black" stroke-width="2"/>
</marker>
<marker id="big_open_circle" markerHeight="20" markerWidth="20" orient="auto" refX="20" refY="20" viewBox="0 0 40 40">
<circle cx="20" cy="20" fill="white" r="6" stroke="black" stroke-width="2"/>
</marker>
</defs>
<style type="text/css">
line,path {
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
line.dashed {
stroke-dasharray: 5;
}
circle.solid {
fill:black;
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
circle.open {
fill:none;
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
tspan.head{
fill: none;
stroke: none;
}
</style>
<rect fill="white" height="208" width="768" x="0" y="0"/>
<g>
<line marker-end="url(#triangle)" x1="76" x2="76" y1="32" y2="172"/>
</g>
<g>
<line x1="124" x2="124" y1="24" y2="56"/>
<line x1="124" x2="164" y1="24" y2="24"/>
<line x1="124" x2="124" y1="56" y2="88"/>
<line x1="124" x2="164" y1="56" y2="56"/>
<line x1="124" x2="124" y1="88" y2="120"/>
<line x1="124" x2="164" y1="88" y2="88"/>
<line x1="124" x2="124" y1="120" y2="152"/>
<line x1="124" x2="164" y1="120" y2="120"/>
<line x1="124" x2="124" y1="152" y2="184"/>
<line x1="124" x2="164" y1="152" y2="152"/>
<line x1="124" x2="164" y1="184" y2="184"/>
<line x1="164" x2="164" y1="24" y2="56"/>
<line x1="164" x2="164" y1="56" y2="88"/>
<line x1="164" x2="164" y1="88" y2="120"/>
<line x1="164" x2="164" y1="120" y2="152"/>
<line x1="164" x2="164" y1="152" y2="184"/>
</g>
<g>
<line x1="188" x2="188" y1="144" y2="160"/>
</g>
<g>
<line x1="200" x2="208" y1="128" y2="112"/>
</g>
<g>
<line x1="224" x2="236" y1="112" y2="136"/>
</g>
<g>
<line x1="232" x2="240" y1="96" y2="80"/>
</g>
<g>
<line x1="236" x2="236" y1="144" y2="160"/>
</g>
<g>
<line x1="260" x2="260" y1="144" y2="160"/>
</g>
<g>
<line x1="264" x2="272" y1="64" y2="48"/>
</g>
<g>
<line x1="272" x2="280" y1="80" y2="96"/>
</g>
<g>
<line x1="272" x2="280" y1="128" y2="112"/>
</g>
<g>
<line x1="304" x2="316" y1="112" y2="136"/>
</g>
<g>
<line x1="316" x2="316" y1="144" y2="160"/>
</g>
<g>
<line x1="348" x2="360" y1="136" y2="112"/>
</g>
<g>
<line x1="348" x2="348" y1="144" y2="160"/>
</g>
<g>
<line x1="368" x2="376" y1="96" y2="80"/>
</g>
<g>
<line x1="376" x2="384" y1="48" y2="64"/>
</g>
<g>
<line x1="376" x2="388" y1="112" y2="136"/>
</g>
<g>
<line x1="388" x2="388" y1="144" y2="160"/>
</g>
<g>
<line x1="416" x2="424" y1="80" y2="96"/>
</g>
<g>
<line x1="420" x2="420" y1="144" y2="160"/>
</g>
<g>
<line x1="436" x2="420" y1="104" y2="136"/>
</g>
<g>
<line x1="448" x2="460" y1="112" y2="136"/>
</g>
<g>
<line x1="460" x2="460" y1="144" y2="160"/>
</g>
<g>
<line x1="512" x2="640" y1="24" y2="24"/>
</g>
<g>
<text x="17" y="108">
time
</text>
</g>
<g>
<text x="137" y="44">
L1
</text>
</g>
<g>
<text x="137" y="76">
L2
</text>
</g>
<g>
<text x="137" y="108">
L3
</text>
</g>
<g>
<text x="137" y="140">
L4
</text>
</g>
<g>
<text x="137" y="172">
L5
</text>
</g>
<g>
<text x="185" y="140">
x
</text>
</g>
<g>
<text x="185" y="172">
xx
</text>
</g>
<g>
<text x="209" y="108">
E3
</text>
</g>
<g>
<text x="225" y="172">
xx
</text>
</g>
<g>
<text x="249" y="76">
E2
</text>
</g>
<g>
<text x="257" y="140">
E4
</text>
</g>
<g>
<text x="257" y="172">
xx
</text>
</g>
<g>
<text x="289" y="108">
x
</text>
</g>
<g>
<text x="305" y="172">
E5
</text>
</g>
<g>
<text x="313" y="44">
E1
</text>
</g>
<g>
<text x="337" y="172">
xx
</text>
</g>
<g>
<text x="361" y="108">
E3&#39;
</text>
</g>
<g>
<text x="377" y="172">
xx
</text>
</g>
<g>
<text x="393" y="76">
x
</text>
</g>
<g>
<text x="409" y="172">
xx
</text>
</g>
<g>
<text x="449" y="172">
xx
</text>
</g>
<g>
<text x="513" y="12">
validator
</text>
</g>
<g>
<text x="513" y="60">
vote(E1)
</text>
</g>
<g>
<text x="513" y="92">
vote(E2)
</text>
</g>
<g>
<text x="513" y="124">
slash(E3)
</text>
</g>
<g>
<text x="513" y="156">
vote(E4)
</text>
</g>
<g>
<text x="513" y="188">
hang
</text>
</g>
<g>
<text x="553" y="188">
on
</text>
</g>
<g>
<text x="577" y="188">
to
</text>
</g>
<g>
<text x="593" y="12">
action
</text>
</g>
<g>
<text x="601" y="188">
E4
</text>
</g>
<g>
<text x="625" y="188">
and
</text>
</g>
<g>
<text x="657" y="188">
E5
</text>
</g>
<g>
<text x="681" y="188">
for
</text>
</g>
<g>
<text x="713" y="188">
more...
</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

@@ -0,0 +1,92 @@
<svg class="bob" font-family="arial" font-size="14" height="144" width="48" xmlns="http://www.w3.org/2000/svg">
<defs>
<marker id="triangle" markerHeight="8" markerWidth="8" orient="auto" refX="4" refY="2" viewBox="0 0 8 4">
<polygon fill="black" points="0,0 0,4 8,2 0,0"/>
</marker>
<marker id="clear_triangle" markerHeight="10" markerWidth="10" orient="auto" refX="1" refY="7" viewBox="0 0 20 14">
<polygon fill="none" points="2,2 2,12 18,7 2,2" stroke="black" stroke-width="2"/>
</marker>
<marker id="circle" markerHeight="5" markerWidth="5" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<circle cx="10" cy="10" fill="black" r="8"/>
</marker>
<marker id="square" markerHeight="5" markerWidth="5" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<rect fill="black" height="20" width="20" x="0" y="0"/>
</marker>
<marker id="open_circle" markerHeight="10" markerWidth="10" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<circle cx="10" cy="10" fill="white" r="4" stroke="black" stroke-width="2"/>
</marker>
<marker id="big_open_circle" markerHeight="20" markerWidth="20" orient="auto" refX="20" refY="20" viewBox="0 0 40 40">
<circle cx="20" cy="20" fill="white" r="6" stroke="black" stroke-width="2"/>
</marker>
</defs>
<style type="text/css">
line,path {
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
line.dashed {
stroke-dasharray: 5;
}
circle.solid {
fill:black;
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
circle.open {
fill:none;
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
tspan.head{
fill: none;
stroke: none;
}
</style>
<rect fill="white" height="144" width="48" x="0" y="0"/>
<g>
<line x1="20" x2="24" y1="88" y2="80"/>
<line x1="20" x2="20" y1="96" y2="88"/>
<line x1="20" x2="20" y1="96" y2="128"/>
<line x1="24" x2="40" y1="80" y2="48"/>
</g>
<g>
<line x1="44" x2="44" y1="16" y2="32"/>
</g>
<g>
<line x1="44" x2="44" y1="48" y2="96"/>
</g>
<g>
<text x="17" y="140">
5
</text>
</g>
<g>
<text x="41" y="12">
1
</text>
</g>
<g>
<text x="41" y="44">
2
</text>
</g>
<g>
<text x="41" y="108">
4
</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -0,0 +1,92 @@
<svg class="bob" font-family="arial" font-size="14" height="176" width="40" xmlns="http://www.w3.org/2000/svg">
<defs>
<marker id="triangle" markerHeight="8" markerWidth="8" orient="auto" refX="4" refY="2" viewBox="0 0 8 4">
<polygon fill="black" points="0,0 0,4 8,2 0,0"/>
</marker>
<marker id="clear_triangle" markerHeight="10" markerWidth="10" orient="auto" refX="1" refY="7" viewBox="0 0 20 14">
<polygon fill="none" points="2,2 2,12 18,7 2,2" stroke="black" stroke-width="2"/>
</marker>
<marker id="circle" markerHeight="5" markerWidth="5" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<circle cx="10" cy="10" fill="black" r="8"/>
</marker>
<marker id="square" markerHeight="5" markerWidth="5" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<rect fill="black" height="20" width="20" x="0" y="0"/>
</marker>
<marker id="open_circle" markerHeight="10" markerWidth="10" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<circle cx="10" cy="10" fill="white" r="4" stroke="black" stroke-width="2"/>
</marker>
<marker id="big_open_circle" markerHeight="20" markerWidth="20" orient="auto" refX="20" refY="20" viewBox="0 0 40 40">
<circle cx="20" cy="20" fill="white" r="6" stroke="black" stroke-width="2"/>
</marker>
</defs>
<style type="text/css">
line,path {
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
line.dashed {
stroke-dasharray: 5;
}
circle.solid {
fill:black;
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
circle.open {
fill:none;
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
tspan.head{
fill: none;
stroke: none;
}
</style>
<rect fill="white" height="176" width="40" x="0" y="0"/>
<g>
<line x1="12" x2="12" y1="16" y2="32"/>
</g>
<g>
<line x1="12" x2="12" y1="48" y2="128"/>
</g>
<g>
<line x1="16" x2="32" y1="48" y2="80"/>
<line x1="36" x2="32" y1="88" y2="80"/>
<line x1="36" x2="36" y1="96" y2="88"/>
<line x1="36" x2="36" y1="96" y2="160"/>
</g>
<g>
<text x="9" y="12">
1
</text>
</g>
<g>
<text x="9" y="44">
3
</text>
</g>
<g>
<text x="9" y="140">
6
</text>
</g>
<g>
<text x="33" y="172">
7
</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -0,0 +1,122 @@
<svg class="bob" font-family="arial" font-size="14" height="208" width="96" xmlns="http://www.w3.org/2000/svg">
<defs>
<marker id="triangle" markerHeight="8" markerWidth="8" orient="auto" refX="4" refY="2" viewBox="0 0 8 4">
<polygon fill="black" points="0,0 0,4 8,2 0,0"/>
</marker>
<marker id="clear_triangle" markerHeight="10" markerWidth="10" orient="auto" refX="1" refY="7" viewBox="0 0 20 14">
<polygon fill="none" points="2,2 2,12 18,7 2,2" stroke="black" stroke-width="2"/>
</marker>
<marker id="circle" markerHeight="5" markerWidth="5" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<circle cx="10" cy="10" fill="black" r="8"/>
</marker>
<marker id="square" markerHeight="5" markerWidth="5" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<rect fill="black" height="20" width="20" x="0" y="0"/>
</marker>
<marker id="open_circle" markerHeight="10" markerWidth="10" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<circle cx="10" cy="10" fill="white" r="4" stroke="black" stroke-width="2"/>
</marker>
<marker id="big_open_circle" markerHeight="20" markerWidth="20" orient="auto" refX="20" refY="20" viewBox="0 0 40 40">
<circle cx="20" cy="20" fill="white" r="6" stroke="black" stroke-width="2"/>
</marker>
</defs>
<style type="text/css">
line,path {
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
line.dashed {
stroke-dasharray: 5;
}
circle.solid {
fill:black;
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
circle.open {
fill:none;
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
tspan.head{
fill: none;
stroke: none;
}
</style>
<rect fill="white" height="208" width="96" x="0" y="0"/>
<g>
<line x1="20" x2="24" y1="88" y2="80"/>
<line x1="20" x2="20" y1="96" y2="88"/>
<line x1="20" x2="20" y1="96" y2="128"/>
<line x1="24" x2="40" y1="80" y2="48"/>
</g>
<g>
<line x1="44" x2="44" y1="16" y2="32"/>
</g>
<g>
<line x1="44" x2="44" y1="48" y2="96"/>
</g>
<g>
<line x1="48" x2="64" y1="16" y2="48"/>
<line x1="68" x2="64" y1="56" y2="48"/>
<line x1="68" x2="68" y1="64" y2="56"/>
</g>
<g>
<line x1="68" x2="68" y1="80" y2="160"/>
</g>
<g>
<line x1="72" x2="80" y1="80" y2="96"/>
<line x1="80" x2="88" y1="96" y2="112"/>
<line x1="92" x2="88" y1="120" y2="112"/>
<line x1="92" x2="92" y1="128" y2="120"/>
<line x1="92" x2="92" y1="128" y2="192"/>
</g>
<g>
<text x="17" y="140">
5
</text>
</g>
<g>
<text x="41" y="12">
1
</text>
</g>
<g>
<text x="41" y="44">
2
</text>
</g>
<g>
<text x="41" y="108">
4
</text>
</g>
<g>
<text x="65" y="76">
3
</text>
</g>
<g>
<text x="65" y="172">
6
</text>
</g>
<g>
<text x="89" y="204">
7
</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

Before

Width:  |  Height:  |  Size: 256 KiB

After

Width:  |  Height:  |  Size: 256 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 KiB

View File

Before

Width:  |  Height:  |  Size: 269 KiB

After

Width:  |  Height:  |  Size: 269 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 269 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 269 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 269 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 269 KiB

View File

@@ -0,0 +1,238 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1"
width="1320px" height="487px"
viewBox="0 0 1320 487"
xmlns="http://www.w3.org/2000/svg" shape-rendering="crispEdges"
stroke-width="1" text-rendering="geometricPrecision">
<polygon fill="white" points="101,7 161,7 161,16 101,16"/>
<text x="132" y="16" textLength="59" font-family="Helvetica" font-size="12" fill="black" text-anchor="middle">
VoteSigner
</text>
<polygon fill="white" points="371,7 419,7 419,16 371,16"/>
<text x="396" y="16" textLength="47" font-family="Helvetica" font-size="12" fill="black" text-anchor="middle">
Validator
</text>
<polygon fill="white" points="639,7 679,7 679,16 639,16"/>
<text x="660" y="16" textLength="38" font-family="Helvetica" font-size="12" fill="black" text-anchor="middle">
Cluster
</text>
<polygon fill="white" points="901,7 945,7 945,16 901,16"/>
<text x="924" y="16" textLength="43" font-family="Helvetica" font-size="12" fill="black" text-anchor="middle">
StakerX
</text>
<polygon fill="white" points="1165,7 1209,7 1209,16 1165,16"/>
<text x="1188" y="16" textLength="43" font-family="Helvetica" font-size="12" fill="black" text-anchor="middle">
StakerY
</text>
<line x1="132" y1="22" x2="132" y2="39" stroke="black"/>
<line x1="396" y1="22" x2="396" y2="39" stroke="black"/>
<line x1="660" y1="22" x2="660" y2="39" stroke="black"/>
<line x1="924" y1="22" x2="924" y2="39" stroke="black"/>
<line x1="1188" y1="22" x2="1188" y2="39" stroke="black"/>
<line x1="132" y1="39" x2="132" y2="67" stroke="black"/>
<line x1="396" y1="39" x2="396" y2="67" stroke="black"/>
<line x1="660" y1="39" x2="660" y2="67" stroke="black"/>
<line x1="924" y1="39" x2="924" y2="67" stroke="black"/>
<line x1="1188" y1="39" x2="1188" y2="67" stroke="black"/>
<polygon fill="white" points="272,39 520,39 520,61 272,61"/>
<line x1="272" y1="39" x2="520" y2="39" stroke="black"/>
<line x1="272" y1="61" x2="520" y2="61" stroke="black"/>
<line x1="272" y1="39" x2="272" y2="61" stroke="black"/>
<line x1="520" y1="39" x2="520" y2="61" stroke="black"/>
<polygon fill="white" points="379,46 411,46 411,55 379,55"/>
<text x="380" y="55" textLength="30" font-family="Helvetica" font-size="12" fill="black">
boot..
</text>
<line x1="132" y1="67" x2="132" y2="106" stroke="black"/>
<line x1="396" y1="67" x2="396" y2="106" stroke="black"/>
<line x1="660" y1="67" x2="660" y2="106" stroke="black"/>
<line x1="924" y1="67" x2="924" y2="106" stroke="black"/>
<line x1="1188" y1="67" x2="1188" y2="106" stroke="black"/>
<line x1="132" y1="82" x2="396" y2="82" stroke="black"/>
<line x1="132" y1="84" x2="396" y2="84" stroke="black"/>
<polygon fill="black" points="396,83 386,89 386,77"/>
<polygon fill="black" points="132,83 142,89 142,77"/>
<polygon fill="white" points="242,68 284,68 284,77 242,77"/>
<text x="243" y="77" textLength="40" font-family="Helvetica" font-size="12" fill="black">
register
</text>
<polygon fill="white" points="262,79 264,79 264,88 262,88"/>
<text x="263" y="88" textLength="0" font-family="Helvetica" font-size="12" fill="black">
</text>
<polygon fill="white" points="237,90 289,90 289,99 237,99"/>
<text x="238" y="99" textLength="50" font-family="Helvetica" font-size="12" fill="black">
(optional)
</text>
<line x1="132" y1="106" x2="132" y2="134" stroke="black"/>
<line x1="396" y1="106" x2="396" y2="134" stroke="black"/>
<line x1="660" y1="106" x2="660" y2="134" stroke="black"/>
<line x1="924" y1="106" x2="924" y2="134" stroke="black"/>
<line x1="1188" y1="106" x2="1188" y2="134" stroke="black"/>
<line x1="396" y1="117" x2="660" y2="117" stroke="black"/>
<polygon fill="black" points="660,117 650,123 650,111"/>
<polygon fill="white" points="441,107 613,107 613,116 441,116"/>
<text x="442" y="116" textLength="170" font-family="Helvetica" font-size="12" fill="black">
VoteState::Initialize(VoteSigner)
</text>
<line x1="132" y1="134" x2="132" y2="162" stroke="black"/>
<line x1="396" y1="134" x2="396" y2="162" stroke="black"/>
<line x1="660" y1="134" x2="660" y2="162" stroke="black"/>
<line x1="924" y1="134" x2="924" y2="162" stroke="black"/>
<line x1="1188" y1="134" x2="1188" y2="162" stroke="black"/>
<line x1="924" y1="145" x2="660" y2="145" stroke="black"/>
<polygon fill="black" points="660,145 670,151 670,139"/>
<polygon fill="white" points="706,135 877,135 877,144 706,144"/>
<text x="707" y="144" textLength="169" font-family="Helvetica" font-size="12" fill="black">
StakeState::Delegate(Validator)
</text>
<line x1="132" y1="162" x2="132" y2="190" stroke="black"/>
<line x1="396" y1="162" x2="396" y2="190" stroke="black"/>
<line x1="660" y1="162" x2="660" y2="190" stroke="black"/>
<line x1="924" y1="162" x2="924" y2="190" stroke="black"/>
<line x1="1188" y1="162" x2="1188" y2="190" stroke="black"/>
<line x1="1188" y1="173" x2="660" y2="173" stroke="black"/>
<polygon fill="black" points="660,173 670,179 670,167"/>
<polygon fill="white" points="838,163 1009,163 1009,172 838,172"/>
<text x="839" y="172" textLength="169" font-family="Helvetica" font-size="12" fill="black">
StakeState::Delegate(Validator)
</text>
<line x1="132" y1="190" x2="132" y2="207" stroke="black"/>
<line x1="396" y1="190" x2="396" y2="207" stroke="black"/>
<line x1="660" y1="190" x2="660" y2="207" stroke="black"/>
<line x1="924" y1="190" x2="924" y2="207" stroke="black"/>
<line x1="1188" y1="190" x2="1188" y2="207" stroke="black"/>
<line x1="132" y1="207" x2="132" y2="246" stroke="black"/>
<line x1="396" y1="207" x2="396" y2="246" stroke="black"/>
<line x1="660" y1="207" x2="660" y2="246" stroke="black"/>
<line x1="924" y1="207" x2="924" y2="246" stroke="black"/>
<line x1="1188" y1="207" x2="1188" y2="246" stroke="black"/>
<polygon fill="white" points="272,207 784,207 784,240 272,240"/>
<line x1="272" y1="207" x2="784" y2="207" stroke="black"/>
<line x1="272" y1="240" x2="784" y2="240" stroke="black"/>
<line x1="272" y1="207" x2="272" y2="240" stroke="black"/>
<line x1="784" y1="207" x2="784" y2="240" stroke="black"/>
<polygon fill="white" points="526,208 528,208 528,217 526,217"/>
<text x="527" y="217" textLength="0" font-family="Helvetica" font-size="12" fill="black">
</text>
<polygon fill="white" points="506,219 549,219 549,228 506,228"/>
<text x="507" y="228" textLength="41" font-family="Helvetica" font-size="12" fill="black">
validate
</text>
<polygon fill="white" points="526,230 528,230 528,239 526,239"/>
<text x="527" y="239" textLength="0" font-family="Helvetica" font-size="12" fill="black">
</text>
<line x1="132" y1="246" x2="132" y2="274" stroke="black"/>
<line x1="396" y1="246" x2="396" y2="274" stroke="black"/>
<line x1="660" y1="246" x2="660" y2="274" stroke="black"/>
<line x1="924" y1="246" x2="924" y2="274" stroke="black"/>
<line x1="1188" y1="246" x2="1188" y2="274" stroke="black"/>
<line x1="396" y1="257" x2="132" y2="257" stroke="black"/>
<polygon fill="black" points="132,257 142,263 142,251"/>
<polygon fill="white" points="236,247 291,247 291,256 236,256"/>
<text x="237" y="256" textLength="53" font-family="Helvetica" font-size="12" fill="black">
sign(vote)
</text>
<line x1="132" y1="274" x2="132" y2="302" stroke="black"/>
<line x1="396" y1="274" x2="396" y2="302" stroke="black"/>
<line x1="660" y1="274" x2="660" y2="302" stroke="black"/>
<line x1="924" y1="274" x2="924" y2="302" stroke="black"/>
<line x1="1188" y1="274" x2="1188" y2="302" stroke="black"/>
<line x1="132" y1="285" x2="396" y2="285" stroke="black" stroke-dasharray="2,2"/>
<polygon fill="black" points="396,285 386,291 386,279"/>
<polygon fill="white" points="232,275 295,275 295,284 232,284"/>
<text x="233" y="284" textLength="61" font-family="Helvetica" font-size="12" fill="black">
signed vote
</text>
<line x1="132" y1="302" x2="132" y2="330" stroke="black"/>
<line x1="396" y1="302" x2="396" y2="330" stroke="black"/>
<line x1="660" y1="302" x2="660" y2="330" stroke="black"/>
<line x1="924" y1="302" x2="924" y2="330" stroke="black"/>
<line x1="1188" y1="302" x2="1188" y2="330" stroke="black"/>
<line x1="396" y1="313" x2="660" y2="313" stroke="black"/>
<polygon fill="black" points="660,313 650,319 650,307"/>
<polygon fill="white" points="494,303 561,303 561,312 494,312"/>
<text x="495" y="312" textLength="65" font-family="Helvetica" font-size="12" fill="black">
gossip(vote)
</text>
<line x1="132" y1="330" x2="132" y2="347" stroke="black" stroke-dasharray="2,2"/>
<line x1="396" y1="330" x2="396" y2="347" stroke="black" stroke-dasharray="2,2"/>
<line x1="660" y1="330" x2="660" y2="347" stroke="black" stroke-dasharray="2,2"/>
<line x1="924" y1="330" x2="924" y2="347" stroke="black" stroke-dasharray="2,2"/>
<line x1="1188" y1="330" x2="1188" y2="347" stroke="black" stroke-dasharray="2,2"/>
<line x1="132" y1="347" x2="132" y2="364" stroke="black" stroke-dasharray="2,2"/>
<line x1="396" y1="347" x2="396" y2="364" stroke="black" stroke-dasharray="2,2"/>
<line x1="660" y1="347" x2="660" y2="364" stroke="black" stroke-dasharray="2,2"/>
<line x1="924" y1="347" x2="924" y2="364" stroke="black" stroke-dasharray="2,2"/>
<line x1="1188" y1="347" x2="1188" y2="364" stroke="black" stroke-dasharray="2,2"/>
<line x1="132" y1="364" x2="132" y2="414" stroke="black"/>
<line x1="396" y1="364" x2="396" y2="414" stroke="black"/>
<line x1="660" y1="364" x2="660" y2="414" stroke="black"/>
<line x1="924" y1="364" x2="924" y2="414" stroke="black"/>
<line x1="1188" y1="364" x2="1188" y2="414" stroke="black"/>
<polygon fill="white" points="278,364 514,364 514,408 278,408"/>
<polygon fill="white" points="278,364 278,408 272,386"/>
<polygon fill="white" points="514,364 514,408 520,386"/>
<line x1="278" y1="364" x2="514" y2="364" stroke="black"/>
<line x1="278" y1="408" x2="514" y2="408" stroke="black"/>
<line x1="278" y1="364" x2="272" y2="386" stroke="black"/>
<line x1="272" y1="386" x2="278" y2="408" stroke="black"/>
<line x1="514" y1="364" x2="520" y2="386" stroke="black"/>
<line x1="520" y1="386" x2="514" y2="408" stroke="black"/>
<polygon fill="white" points="394,365 396,365 396,374 394,374"/>
<text x="395" y="374" textLength="0" font-family="Helvetica" font-size="12" fill="black">
</text>
<polygon fill="white" points="383,376 408,376 408,385 383,385"/>
<text x="384" y="385" textLength="23" font-family="Helvetica" font-size="12" fill="black">
max
</text>
<polygon fill="white" points="375,387 415,387 415,396 375,396"/>
<text x="376" y="396" textLength="38" font-family="Helvetica" font-size="12" fill="black">
lockout
</text>
<polygon fill="white" points="394,398 396,398 396,407 394,407"/>
<text x="395" y="407" textLength="0" font-family="Helvetica" font-size="12" fill="black">
</text>
<line x1="132" y1="414" x2="132" y2="431" stroke="black"/>
<line x1="396" y1="414" x2="396" y2="431" stroke="black"/>
<line x1="660" y1="414" x2="660" y2="431" stroke="black"/>
<line x1="924" y1="414" x2="924" y2="431" stroke="black"/>
<line x1="1188" y1="414" x2="1188" y2="431" stroke="black"/>
<line x1="132" y1="431" x2="132" y2="459" stroke="black"/>
<line x1="396" y1="431" x2="396" y2="459" stroke="black"/>
<line x1="660" y1="431" x2="660" y2="459" stroke="black"/>
<line x1="924" y1="431" x2="924" y2="459" stroke="black"/>
<line x1="1188" y1="431" x2="1188" y2="459" stroke="black"/>
<line x1="924" y1="442" x2="660" y2="442" stroke="black"/>
<polygon fill="black" points="660,442 670,448 670,436"/>
<polygon fill="white" points="712,432 871,432 871,441 712,441"/>
<text x="713" y="441" textLength="157" font-family="Helvetica" font-size="12" fill="black">
StakeState::RedeemCredits()
</text>
<line x1="132" y1="459" x2="132" y2="487" stroke="black"/>
<line x1="396" y1="459" x2="396" y2="487" stroke="black"/>
<line x1="660" y1="459" x2="660" y2="487" stroke="black"/>
<line x1="924" y1="459" x2="924" y2="487" stroke="black"/>
<line x1="1188" y1="459" x2="1188" y2="487" stroke="black"/>
<line x1="1188" y1="470" x2="660" y2="470" stroke="black"/>
<polygon fill="black" points="660,470 670,476 670,464"/>
<polygon fill="white" points="844,460 1003,460 1003,469 844,469"/>
<text x="845" y="469" textLength="157" font-family="Helvetica" font-size="12" fill="black">
StakeState::RedeemCredits()
</text>
<line x1="132" y1="481" x2="132" y2="487" stroke="black"/>
<line x1="396" y1="481" x2="396" y2="487" stroke="black"/>
<line x1="660" y1="481" x2="660" y2="487" stroke="black"/>
<line x1="924" y1="481" x2="924" y2="487" stroke="black"/>
<line x1="1188" y1="481" x2="1188" y2="487" stroke="black"/>
</svg>

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -0,0 +1,346 @@
<svg class="bob" font-family="arial" font-size="14" height="160" width="848" xmlns="http://www.w3.org/2000/svg">
<defs>
<marker id="triangle" markerHeight="8" markerWidth="8" orient="auto" refX="4" refY="2" viewBox="0 0 8 4">
<polygon fill="black" points="0,0 0,4 8,2 0,0"/>
</marker>
<marker id="clear_triangle" markerHeight="10" markerWidth="10" orient="auto" refX="1" refY="7" viewBox="0 0 20 14">
<polygon fill="none" points="2,2 2,12 18,7 2,2" stroke="black" stroke-width="2"/>
</marker>
<marker id="circle" markerHeight="5" markerWidth="5" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<circle cx="10" cy="10" fill="black" r="8"/>
</marker>
<marker id="square" markerHeight="5" markerWidth="5" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<rect fill="black" height="20" width="20" x="0" y="0"/>
</marker>
<marker id="open_circle" markerHeight="10" markerWidth="10" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<circle cx="10" cy="10" fill="white" r="4" stroke="black" stroke-width="2"/>
</marker>
<marker id="big_open_circle" markerHeight="20" markerWidth="20" orient="auto" refX="20" refY="20" viewBox="0 0 40 40">
<circle cx="20" cy="20" fill="white" r="6" stroke="black" stroke-width="2"/>
</marker>
</defs>
<style type="text/css">
line,path {
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
line.dashed {
stroke-dasharray: 5;
}
circle.solid {
fill:black;
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
circle.open {
fill:none;
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
tspan.head{
fill: none;
stroke: none;
}
</style>
<rect fill="white" height="160" width="848" x="0" y="0"/>
<g>
<line marker-end="url(#triangle)" x1="0" x2="28" y1="104" y2="104"/>
</g>
<g>
<line x1="4" x2="4" y1="12" y2="52"/>
<path d="M 4 52 A 4 4 0 0 0 8 56" fill="none"/>
<path d="M 8 8 A 4 4 0 0 0 4 12" fill="none"/>
</g>
<g>
<line x1="8" x2="104" y1="8" y2="8"/>
<path d="M 108 12 A 4 4 0 0 0 104 8" fill="none"/>
</g>
<g>
<line x1="8" x2="104" y1="56" y2="56"/>
<path d="M 104 56 A 4 4 0 0 0 108 52" fill="none"/>
</g>
<g>
<line x1="36" x2="36" y1="92" y2="116"/>
<path d="M 36 116 A 4 4 0 0 0 40 120" fill="none"/>
<path d="M 40 88 A 4 4 0 0 0 36 92" fill="none"/>
</g>
<g>
<line x1="40" x2="160" y1="88" y2="88"/>
<path d="M 164 92 A 4 4 0 0 0 160 88" fill="none"/>
</g>
<g>
<line x1="40" x2="160" y1="120" y2="120"/>
<path d="M 160 120 A 4 4 0 0 0 164 116" fill="none"/>
</g>
<g>
<line x1="108" x2="108" y1="12" y2="24"/>
<line x1="108" x2="108" y1="24" y2="52"/>
<line marker-end="url(#triangle)" x1="108" x2="140" y1="24" y2="24"/>
</g>
<g>
<line x1="156" x2="156" y1="12" y2="36"/>
<path d="M 156 36 A 4 4 0 0 0 160 40" fill="none"/>
<path d="M 160 8 A 4 4 0 0 0 156 12" fill="none"/>
</g>
<g>
<line x1="160" x2="248" y1="8" y2="8"/>
<path d="M 252 12 A 4 4 0 0 0 248 8" fill="none"/>
</g>
<g>
<line x1="160" x2="248" y1="40" y2="40"/>
<path d="M 248 40 A 4 4 0 0 0 252 36" fill="none"/>
</g>
<g>
<line x1="164" x2="164" y1="92" y2="104"/>
<line x1="164" x2="164" y1="104" y2="116"/>
<line marker-end="url(#triangle)" x1="164" x2="196" y1="104" y2="104"/>
</g>
<g>
<line x1="204" x2="204" y1="92" y2="116"/>
<path d="M 204 116 A 4 4 0 0 0 208 120" fill="none"/>
<path d="M 208 88 A 4 4 0 0 0 204 92" fill="none"/>
</g>
<g>
<line x1="208" x2="280" y1="88" y2="88"/>
<path d="M 284 92 A 4 4 0 0 0 280 88" fill="none"/>
</g>
<g>
<line x1="208" x2="280" y1="120" y2="120"/>
<path d="M 280 120 A 4 4 0 0 0 284 116" fill="none"/>
</g>
<g>
<line x1="252" x2="252" y1="12" y2="24"/>
<line x1="252" x2="252" y1="24" y2="36"/>
<line marker-end="url(#triangle)" x1="252" x2="284" y1="24" y2="24"/>
</g>
<g>
<line x1="284" x2="284" y1="92" y2="104"/>
<line x1="284" x2="284" y1="104" y2="116"/>
<line marker-end="url(#triangle)" x1="284" x2="316" y1="104" y2="104"/>
</g>
<g>
<line x1="292" x2="292" y1="12" y2="36"/>
<path d="M 292 36 A 4 4 0 0 0 296 40" fill="none"/>
<path d="M 296 8 A 4 4 0 0 0 292 12" fill="none"/>
</g>
<g>
<line x1="296" x2="416" y1="8" y2="8"/>
<path d="M 420 12 A 4 4 0 0 0 416 8" fill="none"/>
</g>
<g>
<line x1="296" x2="416" y1="40" y2="40"/>
<path d="M 416 40 A 4 4 0 0 0 420 36" fill="none"/>
</g>
<g>
<line x1="324" x2="324" y1="92" y2="132"/>
<path d="M 324 132 A 4 4 0 0 0 328 136" fill="none"/>
<path d="M 328 88 A 4 4 0 0 0 324 92" fill="none"/>
</g>
<g>
<line x1="328" x2="424" y1="88" y2="88"/>
<path d="M 428 92 A 4 4 0 0 0 424 88" fill="none"/>
</g>
<g>
<line x1="328" x2="424" y1="136" y2="136"/>
<path d="M 424 136 A 4 4 0 0 0 428 132" fill="none"/>
</g>
<g>
<line x1="420" x2="420" y1="12" y2="24"/>
<line x1="420" x2="420" y1="24" y2="36"/>
<line marker-end="url(#triangle)" x1="420" x2="452" y1="24" y2="24"/>
</g>
<g>
<line x1="428" x2="428" y1="92" y2="104"/>
<line x1="428" x2="428" y1="104" y2="132"/>
<line marker-end="url(#triangle)" x1="428" x2="460" y1="104" y2="104"/>
</g>
<g>
<line x1="460" x2="460" y1="12" y2="36"/>
<path d="M 460 36 A 4 4 0 0 0 464 40" fill="none"/>
<path d="M 464 8 A 4 4 0 0 0 460 12" fill="none"/>
</g>
<g>
<line x1="464" x2="576" y1="8" y2="8"/>
<path d="M 580 12 A 4 4 0 0 0 576 8" fill="none"/>
</g>
<g>
<line x1="464" x2="576" y1="40" y2="40"/>
<path d="M 576 40 A 4 4 0 0 0 580 36" fill="none"/>
</g>
<g>
<line x1="468" x2="468" y1="92" y2="116"/>
<path d="M 468 116 A 4 4 0 0 0 472 120" fill="none"/>
<path d="M 472 88 A 4 4 0 0 0 468 92" fill="none"/>
</g>
<g>
<line x1="472" x2="608" y1="88" y2="88"/>
<path d="M 612 92 A 4 4 0 0 0 608 88" fill="none"/>
</g>
<g>
<line x1="472" x2="608" y1="120" y2="120"/>
<path d="M 608 120 A 4 4 0 0 0 612 116" fill="none"/>
</g>
<g>
<line x1="580" x2="580" y1="12" y2="24"/>
<line x1="580" x2="580" y1="24" y2="36"/>
<line marker-end="url(#triangle)" x1="580" x2="612" y1="24" y2="24"/>
</g>
<g>
<line x1="612" x2="612" y1="92" y2="104"/>
<line x1="612" x2="612" y1="104" y2="116"/>
<line marker-end="url(#triangle)" x1="612" x2="636" y1="104" y2="104"/>
</g>
<g>
<line x1="620" x2="620" y1="12" y2="36"/>
<path d="M 620 36 A 4 4 0 0 0 624 40" fill="none"/>
<path d="M 624 8 A 4 4 0 0 0 620 12" fill="none"/>
</g>
<g>
<line x1="624" x2="808" y1="8" y2="8"/>
<path d="M 812 12 A 4 4 0 0 0 808 8" fill="none"/>
</g>
<g>
<line x1="624" x2="808" y1="40" y2="40"/>
<path d="M 808 40 A 4 4 0 0 0 812 36" fill="none"/>
</g>
<g>
<line x1="644" x2="644" y1="92" y2="116"/>
<path d="M 644 116 A 4 4 0 0 0 648 120" fill="none"/>
<path d="M 648 88 A 4 4 0 0 0 644 92" fill="none"/>
</g>
<g>
<line x1="648" x2="784" y1="88" y2="88"/>
<path d="M 788 92 A 4 4 0 0 0 784 88" fill="none"/>
</g>
<g>
<line x1="648" x2="784" y1="120" y2="120"/>
<path d="M 784 120 A 4 4 0 0 0 788 116" fill="none"/>
</g>
<g>
<line x1="788" x2="788" y1="92" y2="116"/>
</g>
<g>
<line x1="812" x2="812" y1="12" y2="24"/>
<line x1="812" x2="812" y1="24" y2="36"/>
<line marker-end="url(#triangle)" x1="812" x2="844" y1="24" y2="24"/>
</g>
<g>
<text x="17" y="28">
PoH
</text>
</g>
<g>
<text x="49" y="28">
verify
</text>
</g>
<g>
<text x="49" y="44">
TVU
</text>
</g>
<g>
<text x="49" y="108">
load
</text>
</g>
<g>
<text x="89" y="108">
accounts
</text>
</g>
<g>
<text x="169" y="28">
sigverify
</text>
</g>
<g>
<text x="217" y="108">
execute
</text>
</g>
<g>
<text x="305" y="28">
lock
</text>
</g>
<g>
<text x="337" y="108">
PoH
</text>
</g>
<g>
<text x="345" y="28">
accounts
</text>
</g>
<g>
<text x="361" y="124">
TPU
</text>
</g>
<g>
<text x="369" y="108">
record
</text>
</g>
<g>
<text x="473" y="28">
validate
</text>
</g>
<g>
<text x="481" y="108">
commit
</text>
</g>
<g>
<text x="537" y="108">
accounts
</text>
</g>
<g>
<text x="545" y="28">
fee
</text>
</g>
<g>
<text x="633" y="28">
allocate
</text>
</g>
<g>
<text x="657" y="108">
unlock
</text>
</g>
<g>
<text x="705" y="28">
new
</text>
</g>
<g>
<text x="713" y="108">
accounts
</text>
</g>
<g>
<text x="737" y="28">
accounts
</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.0 KiB

View File

@@ -0,0 +1,237 @@
<svg class="bob" font-family="arial" font-size="14" height="320" width="560" xmlns="http://www.w3.org/2000/svg">
<defs>
<marker id="triangle" markerHeight="8" markerWidth="8" orient="auto" refX="4" refY="2" viewBox="0 0 8 4">
<polygon fill="black" points="0,0 0,4 8,2 0,0"/>
</marker>
<marker id="clear_triangle" markerHeight="10" markerWidth="10" orient="auto" refX="1" refY="7" viewBox="0 0 20 14">
<polygon fill="none" points="2,2 2,12 18,7 2,2" stroke="black" stroke-width="2"/>
</marker>
<marker id="circle" markerHeight="5" markerWidth="5" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<circle cx="10" cy="10" fill="black" r="8"/>
</marker>
<marker id="square" markerHeight="5" markerWidth="5" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<rect fill="black" height="20" width="20" x="0" y="0"/>
</marker>
<marker id="open_circle" markerHeight="10" markerWidth="10" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<circle cx="10" cy="10" fill="white" r="4" stroke="black" stroke-width="2"/>
</marker>
<marker id="big_open_circle" markerHeight="20" markerWidth="20" orient="auto" refX="20" refY="20" viewBox="0 0 40 40">
<circle cx="20" cy="20" fill="white" r="6" stroke="black" stroke-width="2"/>
</marker>
</defs>
<style type="text/css">
line,path {
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
line.dashed {
stroke-dasharray: 5;
}
circle.solid {
fill:black;
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
circle.open {
fill:none;
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
tspan.head{
fill: none;
stroke: none;
}
</style>
<rect fill="white" height="320" width="560" x="0" y="0"/>
<g>
<line x1="20" x2="20" y1="140" y2="196"/>
<path d="M 20 196 A 4 4 0 0 0 24 200" fill="none"/>
<path d="M 24 136 A 4 4 0 0 0 20 140" fill="none"/>
</g>
<g>
<line x1="24" x2="104" y1="136" y2="136"/>
<path d="M 108 140 A 4 4 0 0 0 104 136" fill="none"/>
</g>
<g>
<line x1="24" x2="104" y1="200" y2="200"/>
<path d="M 104 200 A 4 4 0 0 0 108 196" fill="none"/>
</g>
<g>
<line x1="108" x2="108" y1="140" y2="152"/>
<line x1="108" x2="108" y1="152" y2="184"/>
<line x1="108" x2="176" y1="152" y2="152"/>
<line x1="108" x2="108" y1="184" y2="196"/>
<line x1="108" x2="176" y1="184" y2="184"/>
<path d="M 176 152 A 4 4 0 0 0 180 148" fill="none"/>
<path d="M 180 188 A 4 4 0 0 0 176 184" fill="none"/>
</g>
<g>
<line x1="180" x2="180" y1="108" y2="148"/>
<path d="M 184 104 A 4 4 0 0 0 180 108" fill="none"/>
</g>
<g>
<line x1="180" x2="180" y1="188" y2="244"/>
<path d="M 180 244 A 4 4 0 0 0 184 248" fill="none"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="184" x2="252" y1="104" y2="104"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="184" x2="252" y1="248" y2="248"/>
</g>
<g>
<line x1="228" x2="228" y1="28" y2="96"/>
<path d="M 232 24 A 4 4 0 0 0 228 28" fill="none"/>
</g>
<g>
<line x1="228" x2="228" y1="112" y2="240"/>
</g>
<g>
<line x1="228" x2="228" y1="256" y2="308"/>
<path d="M 228 308 A 4 4 0 0 0 232 312" fill="none"/>
</g>
<g>
<line x1="232" x2="552" y1="24" y2="24"/>
<path d="M 556 28 A 4 4 0 0 0 552 24" fill="none"/>
</g>
<g>
<line x1="232" x2="552" y1="312" y2="312"/>
<path d="M 552 312 A 4 4 0 0 0 556 308" fill="none"/>
</g>
<g>
<line x1="260" x2="260" y1="76" y2="132"/>
<path d="M 260 132 A 4 4 0 0 0 264 136" fill="none"/>
<path d="M 264 72 A 4 4 0 0 0 260 76" fill="none"/>
</g>
<g>
<line x1="260" x2="260" y1="220" y2="276"/>
<path d="M 260 276 A 4 4 0 0 0 264 280" fill="none"/>
<path d="M 264 216 A 4 4 0 0 0 260 220" fill="none"/>
</g>
<g>
<line x1="264" x2="360" y1="72" y2="72"/>
<path d="M 364 76 A 4 4 0 0 0 360 72" fill="none"/>
</g>
<g>
<line x1="264" x2="360" y1="136" y2="136"/>
<path d="M 360 136 A 4 4 0 0 0 364 132" fill="none"/>
</g>
<g>
<line x1="264" x2="316" y1="216" y2="216"/>
<line x1="316" x2="316" y1="188" y2="216"/>
<line x1="316" x2="360" y1="216" y2="216"/>
<path d="M 320 184 A 4 4 0 0 0 316 188" fill="none"/>
<path d="M 364 220 A 4 4 0 0 0 360 216" fill="none"/>
</g>
<g>
<line x1="264" x2="360" y1="280" y2="280"/>
<path d="M 360 280 A 4 4 0 0 0 364 276" fill="none"/>
</g>
<g>
<line x1="320" x2="448" y1="184" y2="184"/>
<path d="M 448 184 A 4 4 0 0 0 452 180" fill="none"/>
</g>
<g>
<line x1="364" x2="364" y1="76" y2="104"/>
<line x1="364" x2="364" y1="104" y2="132"/>
<line marker-end="url(#triangle)" x1="364" x2="388" y1="104" y2="104"/>
</g>
<g>
<line x1="364" x2="364" y1="220" y2="248"/>
<line x1="364" x2="364" y1="248" y2="276"/>
<line marker-end="url(#triangle)" x1="364" x2="388" y1="248" y2="248"/>
</g>
<g>
<line x1="396" x2="396" y1="76" y2="132"/>
<path d="M 396 132 A 4 4 0 0 0 400 136" fill="none"/>
<path d="M 400 72 A 4 4 0 0 0 396 76" fill="none"/>
</g>
<g>
<line x1="396" x2="396" y1="220" y2="276"/>
<path d="M 396 276 A 4 4 0 0 0 400 280" fill="none"/>
<path d="M 400 216 A 4 4 0 0 0 396 220" fill="none"/>
</g>
<g>
<line x1="400" x2="496" y1="72" y2="72"/>
<path d="M 500 76 A 4 4 0 0 0 496 72" fill="none"/>
</g>
<g>
<line x1="400" x2="496" y1="136" y2="136"/>
<path d="M 496 136 A 4 4 0 0 0 500 132" fill="none"/>
</g>
<g>
<line x1="400" x2="504" y1="216" y2="216"/>
<path d="M 508 220 A 4 4 0 0 0 504 216" fill="none"/>
</g>
<g>
<line x1="400" x2="504" y1="280" y2="280"/>
<path d="M 504 280 A 4 4 0 0 0 508 276" fill="none"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="452" x2="452" y1="160" y2="148"/>
<line x1="452" x2="452" y1="160" y2="180"/>
</g>
<g>
<line x1="500" x2="500" y1="76" y2="132"/>
</g>
<g>
<line x1="508" x2="508" y1="220" y2="276"/>
</g>
<g>
<line x1="556" x2="556" y1="28" y2="308"/>
</g>
<g>
<text x="41" y="172">
Client
</text>
</g>
<g>
<text x="281" y="108">
Verifier
</text>
</g>
<g>
<text x="281" y="252">
Loader
</text>
</g>
<g>
<text x="329" y="44">
Solana
</text>
</g>
<g>
<text x="337" y="172">
LoadAccounts
</text>
</g>
<g>
<text x="385" y="44">
Runtime
</text>
</g>
<g>
<text x="409" y="252">
Interpreter
</text>
</g>
<g>
<text x="417" y="108">
Accounts
</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@@ -0,0 +1,163 @@
<svg class="bob" font-family="arial" font-size="14" height="288" width="432" xmlns="http://www.w3.org/2000/svg">
<defs>
<marker id="triangle" markerHeight="8" markerWidth="8" orient="auto" refX="4" refY="2" viewBox="0 0 8 4">
<polygon fill="black" points="0,0 0,4 8,2 0,0"/>
</marker>
<marker id="clear_triangle" markerHeight="10" markerWidth="10" orient="auto" refX="1" refY="7" viewBox="0 0 20 14">
<polygon fill="none" points="2,2 2,12 18,7 2,2" stroke="black" stroke-width="2"/>
</marker>
<marker id="circle" markerHeight="5" markerWidth="5" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<circle cx="10" cy="10" fill="black" r="8"/>
</marker>
<marker id="square" markerHeight="5" markerWidth="5" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<rect fill="black" height="20" width="20" x="0" y="0"/>
</marker>
<marker id="open_circle" markerHeight="10" markerWidth="10" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<circle cx="10" cy="10" fill="white" r="4" stroke="black" stroke-width="2"/>
</marker>
<marker id="big_open_circle" markerHeight="20" markerWidth="20" orient="auto" refX="20" refY="20" viewBox="0 0 40 40">
<circle cx="20" cy="20" fill="white" r="6" stroke="black" stroke-width="2"/>
</marker>
</defs>
<style type="text/css">
line,path {
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
line.dashed {
stroke-dasharray: 5;
}
circle.solid {
fill:black;
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
circle.open {
fill:none;
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
tspan.head{
fill: none;
stroke: none;
}
</style>
<rect fill="white" height="288" width="432" x="0" y="0"/>
<g>
<line x1="12" x2="12" y1="248" y2="280"/>
<line x1="12" x2="140" y1="248" y2="248"/>
<line x1="12" x2="140" y1="280" y2="280"/>
<line x1="140" x2="140" y1="248" y2="280"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="112" x2="126" y1="240" y2="212"/>
</g>
<g>
<line x1="124" x2="124" y1="88" y2="120"/>
<line x1="124" x2="268" y1="88" y2="88"/>
<line x1="124" x2="268" y1="120" y2="120"/>
<line x1="268" x2="268" y1="88" y2="120"/>
</g>
<g>
<line x1="124" x2="124" y1="168" y2="200"/>
<line x1="124" x2="180" y1="168" y2="168"/>
<line x1="124" x2="180" y1="200" y2="200"/>
<line x1="180" x2="180" y1="168" y2="200"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="160" x2="174" y1="160" y2="132"/>
</g>
<g>
<line x1="172" x2="172" y1="248" y2="280"/>
<line x1="172" x2="300" y1="248" y2="248"/>
<line x1="172" x2="300" y1="280" y2="280"/>
<line x1="300" x2="300" y1="248" y2="280"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="184" x2="178" y1="224" y2="212"/>
<line x1="184" x2="192" y1="224" y2="240"/>
</g>
<g>
<line x1="212" x2="212" y1="168" y2="200"/>
<line x1="212" x2="428" y1="168" y2="168"/>
<line x1="212" x2="428" y1="200" y2="200"/>
<line x1="428" x2="428" y1="168" y2="200"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="224" x2="218" y1="144" y2="132"/>
<line x1="224" x2="232" y1="144" y2="160"/>
</g>
<g>
<line x1="236" x2="236" y1="8" y2="40"/>
<line x1="236" x2="340" y1="8" y2="8"/>
<line x1="236" x2="340" y1="40" y2="40"/>
<line x1="340" x2="340" y1="8" y2="40"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="248" x2="262" y1="80" y2="52"/>
</g>
<g>
<line x1="308" x2="308" y1="88" y2="120"/>
<line x1="308" x2="420" y1="88" y2="88"/>
<line x1="308" x2="420" y1="120" y2="120"/>
<line x1="420" x2="420" y1="88" y2="120"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="320" x2="314" y1="64" y2="52"/>
<line x1="320" x2="328" y1="64" y2="80"/>
</g>
<g>
<text x="25" y="268">
Hash(Account1)
</text>
</g>
<g>
<text x="137" y="108">
Bank-Diff-Merkle
</text>
</g>
<g>
<text x="137" y="188">
Hash
</text>
</g>
<g>
<text x="185" y="268">
Hash(Account2)
</text>
</g>
<g>
<text x="225" y="188">
Previous
</text>
</g>
<g>
<text x="249" y="28">
Bank-Merkle
</text>
</g>
<g>
<text x="297" y="188">
Bank-Diff-Merkle
</text>
</g>
<g>
<text x="321" y="108">
Block-Merkle
</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -0,0 +1,203 @@
<svg class="bob" font-family="arial" font-size="14" height="304" width="584" xmlns="http://www.w3.org/2000/svg">
<defs>
<marker id="triangle" markerHeight="8" markerWidth="8" orient="auto" refX="4" refY="2" viewBox="0 0 8 4">
<polygon fill="black" points="0,0 0,4 8,2 0,0"/>
</marker>
<marker id="clear_triangle" markerHeight="10" markerWidth="10" orient="auto" refX="1" refY="7" viewBox="0 0 20 14">
<polygon fill="none" points="2,2 2,12 18,7 2,2" stroke="black" stroke-width="2"/>
</marker>
<marker id="circle" markerHeight="5" markerWidth="5" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<circle cx="10" cy="10" fill="black" r="8"/>
</marker>
<marker id="square" markerHeight="5" markerWidth="5" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<rect fill="black" height="20" width="20" x="0" y="0"/>
</marker>
<marker id="open_circle" markerHeight="10" markerWidth="10" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<circle cx="10" cy="10" fill="white" r="4" stroke="black" stroke-width="2"/>
</marker>
<marker id="big_open_circle" markerHeight="20" markerWidth="20" orient="auto" refX="20" refY="20" viewBox="0 0 40 40">
<circle cx="20" cy="20" fill="white" r="6" stroke="black" stroke-width="2"/>
</marker>
</defs>
<style type="text/css">
line,path {
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
line.dashed {
stroke-dasharray: 5;
}
circle.solid {
fill:black;
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
circle.open {
fill:none;
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
tspan.head{
fill: none;
stroke: none;
}
</style>
<rect fill="white" height="304" width="584" x="0" y="0"/>
<g>
<line x1="12" x2="12" y1="248" y2="280"/>
<line x1="12" x2="156" y1="248" y2="248"/>
<line x1="12" x2="156" y1="280" y2="280"/>
<line x1="156" x2="156" y1="248" y2="280"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="128" x2="142" y1="240" y2="212"/>
</g>
<g>
<line x1="148" x2="148" y1="168" y2="200"/>
<line x1="148" x2="212" y1="168" y2="168"/>
<line x1="148" x2="212" y1="200" y2="200"/>
<line x1="212" x2="212" y1="168" y2="200"/>
</g>
<g>
<line x1="180" x2="180" y1="88" y2="120"/>
<line x1="180" x2="292" y1="88" y2="88"/>
<line x1="180" x2="292" y1="120" y2="120"/>
<line x1="292" x2="292" y1="88" y2="120"/>
</g>
<g>
<line x1="188" x2="188" y1="248" y2="280"/>
<line x1="188" x2="332" y1="248" y2="248"/>
<line x1="188" x2="332" y1="280" y2="280"/>
<line x1="332" x2="332" y1="248" y2="280"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="192" x2="206" y1="160" y2="132"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="212" x2="212" y1="224" y2="212"/>
<line x1="212" x2="212" y1="224" y2="240"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="264" x2="278" y1="80" y2="52"/>
</g>
<g>
<line x1="284" x2="284" y1="8" y2="40"/>
<line x1="284" x2="412" y1="8" y2="8"/>
<line x1="284" x2="412" y1="40" y2="40"/>
<line x1="412" x2="412" y1="8" y2="40"/>
</g>
<g>
<line x1="364" x2="364" y1="248" y2="280"/>
<line x1="364" x2="508" y1="248" y2="248"/>
<line x1="364" x2="508" y1="280" y2="280"/>
<line x1="508" x2="508" y1="248" y2="280"/>
</g>
<g>
<line x1="396" x2="396" y1="88" y2="120"/>
<line x1="396" x2="508" y1="88" y2="88"/>
<line x1="396" x2="508" y1="120" y2="120"/>
<line x1="508" x2="508" y1="88" y2="120"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="416" x2="410" y1="64" y2="52"/>
<line x1="416" x2="424" y1="64" y2="80"/>
</g>
<g>
<line x1="468" x2="468" y1="168" y2="200"/>
<line x1="468" x2="532" y1="168" y2="168"/>
<line x1="468" x2="532" y1="200" y2="200"/>
<line x1="532" x2="532" y1="168" y2="200"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="476" x2="476" y1="224" y2="212"/>
<line x1="476" x2="476" y1="224" y2="240"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="480" x2="474" y1="144" y2="132"/>
<line x1="480" x2="488" y1="144" y2="160"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="536" x2="530" y1="224" y2="212"/>
<line x1="536" x2="544" y1="224" y2="240"/>
</g>
<g>
<line x1="540" x2="540" y1="248" y2="280"/>
<line x1="540" x2="572" y1="248" y2="248"/>
<line x1="540" x2="572" y1="280" y2="280"/>
<line x1="572" x2="572" y1="248" y2="280"/>
</g>
<g>
<text x="25" y="268">
Hash(T1,
</text>
</g>
<g>
<text x="97" y="268">
status)
</text>
</g>
<g>
<text x="169" y="188">
Hash
</text>
</g>
<g>
<text x="193" y="108">
Entry-Merkle
</text>
</g>
<g>
<text x="201" y="268">
Hash(T2,
</text>
</g>
<g>
<text x="273" y="268">
status)
</text>
</g>
<g>
<text x="305" y="28">
Block-Merkle
</text>
</g>
<g>
<text x="377" y="268">
Hash(T3,
</text>
</g>
<g>
<text x="409" y="108">
Entry-Merkle
</text>
</g>
<g>
<text x="449" y="268">
status)
</text>
</g>
<g>
<text x="489" y="188">
Hash
</text>
</g>
<g>
<text x="553" y="268">
0
</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@@ -0,0 +1,312 @@
<svg class="bob" font-family="arial" font-size="14" height="304" width="696" xmlns="http://www.w3.org/2000/svg">
<defs>
<marker id="triangle" markerHeight="8" markerWidth="8" orient="auto" refX="4" refY="2" viewBox="0 0 8 4">
<polygon fill="black" points="0,0 0,4 8,2 0,0"/>
</marker>
<marker id="clear_triangle" markerHeight="10" markerWidth="10" orient="auto" refX="1" refY="7" viewBox="0 0 20 14">
<polygon fill="none" points="2,2 2,12 18,7 2,2" stroke="black" stroke-width="2"/>
</marker>
<marker id="circle" markerHeight="5" markerWidth="5" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<circle cx="10" cy="10" fill="black" r="8"/>
</marker>
<marker id="square" markerHeight="5" markerWidth="5" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<rect fill="black" height="20" width="20" x="0" y="0"/>
</marker>
<marker id="open_circle" markerHeight="10" markerWidth="10" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<circle cx="10" cy="10" fill="white" r="4" stroke="black" stroke-width="2"/>
</marker>
<marker id="big_open_circle" markerHeight="20" markerWidth="20" orient="auto" refX="20" refY="20" viewBox="0 0 40 40">
<circle cx="20" cy="20" fill="white" r="6" stroke="black" stroke-width="2"/>
</marker>
</defs>
<style type="text/css">
line,path {
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
line.dashed {
stroke-dasharray: 5;
}
circle.solid {
fill:black;
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
circle.open {
fill:none;
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
tspan.head{
fill: none;
stroke: none;
}
</style>
<rect fill="white" height="304" width="696" x="0" y="0"/>
<g>
<line x1="12" x2="12" y1="140" y2="164"/>
<path d="M 12 164 A 4 4 0 0 0 16 168" fill="none"/>
<path d="M 16 136 A 4 4 0 0 0 12 140" fill="none"/>
</g>
<g>
<line x1="16" x2="88" y1="136" y2="136"/>
<path d="M 92 140 A 4 4 0 0 0 88 136" fill="none"/>
</g>
<g>
<line x1="16" x2="88" y1="168" y2="168"/>
<path d="M 88 168 A 4 4 0 0 0 92 164" fill="none"/>
</g>
<g>
<line x1="92" x2="92" y1="140" y2="164"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="92" x2="124" y1="152" y2="152"/>
</g>
<g>
<line x1="108" x2="108" y1="92" y2="144"/>
<path d="M 112 88 A 4 4 0 0 0 108 92" fill="none"/>
</g>
<g>
<line x1="108" x2="108" y1="160" y2="212"/>
<path d="M 108 212 A 4 4 0 0 0 112 216" fill="none"/>
</g>
<g>
<line x1="112" x2="356" y1="88" y2="88"/>
<line x1="356" x2="396" y1="88" y2="88"/>
<line x1="396" x2="560" y1="88" y2="88"/>
<path d="M 564 92 A 4 4 0 0 0 560 88" fill="none"/>
</g>
<g>
<line x1="112" x2="380" y1="216" y2="216"/>
<line x1="380" x2="560" y1="216" y2="216"/>
<path d="M 560 216 A 4 4 0 0 0 564 212" fill="none"/>
</g>
<g>
<line x1="132" x2="132" y1="124" y2="180"/>
<path d="M 132 180 A 4 4 0 0 0 136 184" fill="none"/>
<path d="M 136 120 A 4 4 0 0 0 132 124" fill="none"/>
</g>
<g>
<line x1="136" x2="192" y1="120" y2="120"/>
<path d="M 196 124 A 4 4 0 0 0 192 120" fill="none"/>
</g>
<g>
<line x1="136" x2="192" y1="184" y2="184"/>
<path d="M 192 184 A 4 4 0 0 0 196 180" fill="none"/>
</g>
<g>
<line x1="196" x2="196" y1="124" y2="180"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="196" x2="212" y1="152" y2="152"/>
</g>
<g>
<line x1="220" x2="220" y1="124" y2="180"/>
<path d="M 220 180 A 4 4 0 0 0 224 184" fill="none"/>
<path d="M 224 120 A 4 4 0 0 0 220 124" fill="none"/>
</g>
<g>
<line x1="224" x2="312" y1="120" y2="120"/>
<path d="M 316 124 A 4 4 0 0 0 312 120" fill="none"/>
</g>
<g>
<line x1="224" x2="312" y1="184" y2="184"/>
<path d="M 312 184 A 4 4 0 0 0 316 180" fill="none"/>
</g>
<g>
<line x1="316" x2="316" y1="124" y2="180"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="316" x2="332" y1="152" y2="152"/>
</g>
<g>
<line x1="324" x2="324" y1="28" y2="52"/>
<path d="M 324 52 A 4 4 0 0 0 328 56" fill="none"/>
<path d="M 328 24 A 4 4 0 0 0 324 28" fill="none"/>
</g>
<g>
<line x1="328" x2="432" y1="24" y2="24"/>
<path d="M 436 28 A 4 4 0 0 0 432 24" fill="none"/>
</g>
<g>
<line x1="328" x2="396" y1="56" y2="56"/>
<line marker-end="url(#triangle)" x1="396" x2="396" y1="56" y2="108"/>
<line x1="396" x2="432" y1="56" y2="56"/>
<path d="M 432 56 A 4 4 0 0 0 436 52" fill="none"/>
</g>
<g>
<line x1="340" x2="340" y1="124" y2="180"/>
<path d="M 340 180 A 4 4 0 0 0 344 184" fill="none"/>
<path d="M 344 120 A 4 4 0 0 0 340 124" fill="none"/>
</g>
<g>
<line x1="344" x2="356" y1="120" y2="120"/>
<line x1="356" x2="356" y1="80" y2="120"/>
<line x1="356" x2="416" y1="120" y2="120"/>
<path d="M 420 124 A 4 4 0 0 0 416 120" fill="none"/>
</g>
<g>
<line x1="344" x2="380" y1="184" y2="184"/>
<line marker-end="url(#triangle)" x1="380" x2="380" y1="184" y2="252"/>
<line x1="380" x2="416" y1="184" y2="184"/>
<path d="M 416 184 A 4 4 0 0 0 420 180" fill="none"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="356" x2="356" y1="80" y2="68"/>
</g>
<g>
<line x1="356" x2="356" y1="268" y2="292"/>
<path d="M 356 292 A 4 4 0 0 0 360 296" fill="none"/>
<path d="M 360 264 A 4 4 0 0 0 356 268" fill="none"/>
</g>
<g>
<line x1="360" x2="408" y1="264" y2="264"/>
<path d="M 412 268 A 4 4 0 0 0 408 264" fill="none"/>
</g>
<g>
<line x1="360" x2="408" y1="296" y2="296"/>
<path d="M 408 296 A 4 4 0 0 0 412 292" fill="none"/>
</g>
<g>
<line x1="412" x2="412" y1="268" y2="292"/>
</g>
<g>
<line x1="420" x2="420" y1="124" y2="180"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="420" x2="436" y1="152" y2="152"/>
</g>
<g>
<line x1="436" x2="436" y1="28" y2="52"/>
</g>
<g>
<line x1="444" x2="444" y1="124" y2="180"/>
<path d="M 444 180 A 4 4 0 0 0 448 184" fill="none"/>
<path d="M 448 120 A 4 4 0 0 0 444 124" fill="none"/>
</g>
<g>
<line x1="448" x2="536" y1="120" y2="120"/>
<path d="M 540 124 A 4 4 0 0 0 536 120" fill="none"/>
</g>
<g>
<line x1="448" x2="536" y1="184" y2="184"/>
<path d="M 536 184 A 4 4 0 0 0 540 180" fill="none"/>
</g>
<g>
<line x1="540" x2="540" y1="124" y2="180"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="540" x2="580" y1="152" y2="152"/>
</g>
<g>
<line x1="564" x2="564" y1="92" y2="144"/>
</g>
<g>
<line x1="564" x2="564" y1="160" y2="212"/>
</g>
<g>
<line x1="588" x2="588" y1="124" y2="180"/>
<path d="M 588 180 A 4 4 0 0 0 592 184" fill="none"/>
<path d="M 592 120 A 4 4 0 0 0 588 124" fill="none"/>
</g>
<g>
<line x1="592" x2="688" y1="120" y2="120"/>
<path d="M 692 124 A 4 4 0 0 0 688 120" fill="none"/>
</g>
<g>
<line x1="592" x2="688" y1="184" y2="184"/>
<path d="M 688 184 A 4 4 0 0 0 692 180" fill="none"/>
</g>
<g>
<line x1="692" x2="692" y1="124" y2="180"/>
</g>
<g>
<text x="25" y="156">
Clients
</text>
</g>
<g>
<text x="121" y="108">
TPU
</text>
</g>
<g>
<text x="145" y="140">
Fetch
</text>
</g>
<g>
<text x="145" y="156">
Stage
</text>
</g>
<g>
<text x="233" y="140">
SigVerify
</text>
</g>
<g>
<text x="233" y="156">
Stage
</text>
</g>
<g>
<text x="337" y="44">
PoH
</text>
</g>
<g>
<text x="353" y="140">
Banking
</text>
</g>
<g>
<text x="353" y="156">
Stage
</text>
</g>
<g>
<text x="369" y="44">
Service
</text>
</g>
<g>
<text x="369" y="284">
Bank
</text>
</g>
<g>
<text x="457" y="140">
Broadcast
</text>
</g>
<g>
<text x="457" y="156">
Stage
</text>
</g>
<g>
<text x="601" y="140">
Downstream
</text>
</g>
<g>
<text x="601" y="156">
Validators
</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.4 KiB

View File

@@ -0,0 +1,311 @@
<svg class="bob" font-family="arial" font-size="14" height="352" width="616" xmlns="http://www.w3.org/2000/svg">
<defs>
<marker id="triangle" markerHeight="8" markerWidth="8" orient="auto" refX="4" refY="2" viewBox="0 0 8 4">
<polygon fill="black" points="0,0 0,4 8,2 0,0"/>
</marker>
<marker id="clear_triangle" markerHeight="10" markerWidth="10" orient="auto" refX="1" refY="7" viewBox="0 0 20 14">
<polygon fill="none" points="2,2 2,12 18,7 2,2" stroke="black" stroke-width="2"/>
</marker>
<marker id="circle" markerHeight="5" markerWidth="5" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<circle cx="10" cy="10" fill="black" r="8"/>
</marker>
<marker id="square" markerHeight="5" markerWidth="5" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<rect fill="black" height="20" width="20" x="0" y="0"/>
</marker>
<marker id="open_circle" markerHeight="10" markerWidth="10" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<circle cx="10" cy="10" fill="white" r="4" stroke="black" stroke-width="2"/>
</marker>
<marker id="big_open_circle" markerHeight="20" markerWidth="20" orient="auto" refX="20" refY="20" viewBox="0 0 40 40">
<circle cx="20" cy="20" fill="white" r="6" stroke="black" stroke-width="2"/>
</marker>
</defs>
<style type="text/css">
line,path {
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
line.dashed {
stroke-dasharray: 5;
}
circle.solid {
fill:black;
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
circle.open {
fill:none;
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
tspan.head{
fill: none;
stroke: none;
}
</style>
<rect fill="white" height="352" width="616" x="0" y="0"/>
<g>
<line x1="12" x2="12" y1="156" y2="196"/>
<path d="M 12 196 A 4 4 0 0 0 16 200" fill="none"/>
<path d="M 16 152 A 4 4 0 0 0 12 156" fill="none"/>
</g>
<g>
<line x1="16" x2="112" y1="152" y2="152"/>
<path d="M 116 156 A 4 4 0 0 0 112 152" fill="none"/>
</g>
<g>
<line x1="16" x2="112" y1="200" y2="200"/>
<path d="M 112 200 A 4 4 0 0 0 116 196" fill="none"/>
</g>
<g>
<line x1="116" x2="116" y1="156" y2="168"/>
<line x1="116" x2="116" y1="168" y2="196"/>
<line marker-end="url(#triangle)" x1="116" x2="164" y1="168" y2="168"/>
</g>
<g>
<line x1="148" x2="148" y1="92" y2="160"/>
<path d="M 152 88 A 4 4 0 0 0 148 92" fill="none"/>
</g>
<g>
<line x1="148" x2="148" y1="176" y2="244"/>
<path d="M 148 244 A 4 4 0 0 0 152 248" fill="none"/>
</g>
<g>
<line x1="152" x2="444" y1="88" y2="88"/>
<line x1="444" x2="608" y1="88" y2="88"/>
<path d="M 612 92 A 4 4 0 0 0 608 88" fill="none"/>
</g>
<g>
<line x1="152" x2="220" y1="248" y2="248"/>
<line x1="220" x2="308" y1="248" y2="248"/>
<line x1="308" x2="444" y1="248" y2="248"/>
<line x1="444" x2="608" y1="248" y2="248"/>
<path d="M 608 248 A 4 4 0 0 0 612 244" fill="none"/>
</g>
<g>
<line x1="172" x2="172" y1="140" y2="196"/>
<path d="M 172 196 A 4 4 0 0 0 176 200" fill="none"/>
<path d="M 176 136 A 4 4 0 0 0 172 140" fill="none"/>
</g>
<g>
<line x1="176" x2="232" y1="136" y2="136"/>
<path d="M 236 140 A 4 4 0 0 0 232 136" fill="none"/>
</g>
<g>
<line x1="176" x2="232" y1="200" y2="200"/>
<path d="M 232 200 A 4 4 0 0 0 236 196" fill="none"/>
</g>
<g>
<line x1="212" x2="212" y1="300" y2="340"/>
<path d="M 212 340 A 4 4 0 0 0 216 344" fill="none"/>
<path d="M 216 296 A 4 4 0 0 0 212 300" fill="none"/>
</g>
<g>
<line x1="216" x2="312" y1="344" y2="344"/>
<path d="M 312 344 A 4 4 0 0 0 316 340" fill="none"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="220" x2="220" y1="224" y2="212"/>
<line x1="220" x2="220" y1="224" y2="296"/>
<line x1="220" x2="216" y1="296" y2="296"/>
<line x1="220" x2="312" y1="296" y2="296"/>
<path d="M 316 300 A 4 4 0 0 0 312 296" fill="none"/>
</g>
<g>
<line x1="236" x2="236" y1="140" y2="168"/>
<line x1="236" x2="236" y1="168" y2="196"/>
<line marker-end="url(#triangle)" x1="236" x2="260" y1="168" y2="168"/>
</g>
<g>
<line x1="268" x2="268" y1="140" y2="196"/>
<path d="M 268 196 A 4 4 0 0 0 272 200" fill="none"/>
<path d="M 272 136 A 4 4 0 0 0 268 140" fill="none"/>
</g>
<g>
<line x1="272" x2="368" y1="136" y2="136"/>
<path d="M 372 140 A 4 4 0 0 0 368 136" fill="none"/>
</g>
<g>
<line x1="272" x2="308" y1="200" y2="200"/>
<line marker-end="url(#triangle)" x1="308" x2="308" y1="200" y2="284"/>
<line x1="308" x2="368" y1="200" y2="200"/>
<path d="M 368 200 A 4 4 0 0 0 372 196" fill="none"/>
</g>
<g>
<line x1="316" x2="316" y1="300" y2="340"/>
</g>
<g>
<line x1="372" x2="372" y1="140" y2="168"/>
<line x1="372" x2="372" y1="168" y2="196"/>
<line marker-end="url(#triangle)" x1="372" x2="396" y1="168" y2="168"/>
</g>
<g>
<line x1="404" x2="404" y1="12" y2="36"/>
<path d="M 404 36 A 4 4 0 0 0 408 40" fill="none"/>
<path d="M 408 8 A 4 4 0 0 0 404 12" fill="none"/>
</g>
<g>
<line x1="404" x2="404" y1="140" y2="196"/>
<path d="M 404 196 A 4 4 0 0 0 408 200" fill="none"/>
<path d="M 408 136 A 4 4 0 0 0 404 140" fill="none"/>
</g>
<g>
<line x1="408" x2="472" y1="8" y2="8"/>
<path d="M 476 12 A 4 4 0 0 0 472 8" fill="none"/>
</g>
<g>
<line x1="408" x2="472" y1="40" y2="40"/>
<path d="M 472 40 A 4 4 0 0 0 476 36" fill="none"/>
</g>
<g>
<line x1="408" x2="444" y1="136" y2="136"/>
<line x1="444" x2="444" y1="64" y2="136"/>
<line x1="444" x2="472" y1="136" y2="136"/>
<path d="M 476 140 A 4 4 0 0 0 472 136" fill="none"/>
</g>
<g>
<line x1="408" x2="444" y1="200" y2="200"/>
<line marker-end="url(#triangle)" x1="444" x2="444" y1="200" y2="284"/>
<line x1="444" x2="472" y1="200" y2="200"/>
<path d="M 472 200 A 4 4 0 0 0 476 196" fill="none"/>
</g>
<g>
<line x1="420" x2="420" y1="300" y2="324"/>
<path d="M 420 324 A 4 4 0 0 0 424 328" fill="none"/>
<path d="M 424 296 A 4 4 0 0 0 420 300" fill="none"/>
</g>
<g>
<line x1="424" x2="472" y1="296" y2="296"/>
<path d="M 476 300 A 4 4 0 0 0 472 296" fill="none"/>
</g>
<g>
<line x1="424" x2="472" y1="328" y2="328"/>
<path d="M 472 328 A 4 4 0 0 0 476 324" fill="none"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="444" x2="444" y1="64" y2="52"/>
</g>
<g>
<line x1="476" x2="476" y1="12" y2="36"/>
</g>
<g>
<line x1="476" x2="476" y1="140" y2="168"/>
<line x1="476" x2="476" y1="168" y2="196"/>
<line marker-end="url(#triangle)" x1="476" x2="500" y1="168" y2="168"/>
</g>
<g>
<line x1="476" x2="476" y1="300" y2="324"/>
</g>
<g>
<line x1="508" x2="508" y1="140" y2="196"/>
<path d="M 508 196 A 4 4 0 0 0 512 200" fill="none"/>
<path d="M 512 136 A 4 4 0 0 0 508 140" fill="none"/>
</g>
<g>
<line x1="512" x2="584" y1="136" y2="136"/>
<path d="M 588 140 A 4 4 0 0 0 584 136" fill="none"/>
</g>
<g>
<line x1="512" x2="584" y1="200" y2="200"/>
<path d="M 584 200 A 4 4 0 0 0 588 196" fill="none"/>
</g>
<g>
<line x1="588" x2="588" y1="140" y2="196"/>
</g>
<g>
<line x1="612" x2="612" y1="92" y2="244"/>
</g>
<g>
<text x="25" y="172">
Upstream
</text>
</g>
<g>
<text x="25" y="188">
Validators
</text>
</g>
<g>
<text x="169" y="108">
TVU
</text>
</g>
<g>
<text x="185" y="156">
Blob
</text>
</g>
<g>
<text x="185" y="172">
Fetch
</text>
</g>
<g>
<text x="185" y="188">
Stage
</text>
</g>
<g>
<text x="225" y="316">
Gossip
</text>
</g>
<g>
<text x="225" y="332">
Service
</text>
</g>
<g>
<text x="281" y="156">
Retransmit
</text>
</g>
<g>
<text x="281" y="172">
Stage
</text>
</g>
<g>
<text x="417" y="28">
Leader
</text>
</g>
<g>
<text x="417" y="156">
Replay
</text>
</g>
<g>
<text x="417" y="172">
Stage
</text>
</g>
<g>
<text x="433" y="316">
Bank
</text>
</g>
<g>
<text x="521" y="156">
Storage
</text>
</g>
<g>
<text x="521" y="172">
Stage
</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.7 KiB

View File

@@ -0,0 +1,496 @@
<svg class="bob" font-family="arial" font-size="14" height="960" width="528" xmlns="http://www.w3.org/2000/svg">
<defs>
<marker id="triangle" markerHeight="8" markerWidth="8" orient="auto" refX="4" refY="2" viewBox="0 0 8 4">
<polygon fill="black" points="0,0 0,4 8,2 0,0"/>
</marker>
<marker id="clear_triangle" markerHeight="10" markerWidth="10" orient="auto" refX="1" refY="7" viewBox="0 0 20 14">
<polygon fill="none" points="2,2 2,12 18,7 2,2" stroke="black" stroke-width="2"/>
</marker>
<marker id="circle" markerHeight="5" markerWidth="5" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<circle cx="10" cy="10" fill="black" r="8"/>
</marker>
<marker id="square" markerHeight="5" markerWidth="5" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<rect fill="black" height="20" width="20" x="0" y="0"/>
</marker>
<marker id="open_circle" markerHeight="10" markerWidth="10" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<circle cx="10" cy="10" fill="white" r="4" stroke="black" stroke-width="2"/>
</marker>
<marker id="big_open_circle" markerHeight="20" markerWidth="20" orient="auto" refX="20" refY="20" viewBox="0 0 40 40">
<circle cx="20" cy="20" fill="white" r="6" stroke="black" stroke-width="2"/>
</marker>
</defs>
<style type="text/css">
line,path {
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
line.dashed {
stroke-dasharray: 5;
}
circle.solid {
fill:black;
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
circle.open {
fill:none;
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
tspan.head{
fill: none;
stroke: none;
}
</style>
<rect fill="white" height="960" width="528" x="0" y="0"/>
<g>
<line x1="12" x2="12" y1="188" y2="212"/>
<path d="M 12 212 A 4 4 0 0 0 16 216" fill="none"/>
<path d="M 16 184 A 4 4 0 0 0 12 188" fill="none"/>
</g>
<g>
<line x1="16" x2="80" y1="184" y2="184"/>
<path d="M 84 188 A 4 4 0 0 0 80 184" fill="none"/>
</g>
<g>
<line x1="16" x2="80" y1="216" y2="216"/>
<path d="M 80 216 A 4 4 0 0 0 84 212" fill="none"/>
</g>
<g>
<line x1="20" x2="20" y1="748" y2="788"/>
<path d="M 20 788 A 4 4 0 0 0 24 792" fill="none"/>
<path d="M 24 744 A 4 4 0 0 0 20 748" fill="none"/>
</g>
<g>
<line x1="24" x2="80" y1="744" y2="744"/>
<path d="M 84 748 A 4 4 0 0 0 80 744" fill="none"/>
</g>
<g>
<line x1="24" x2="80" y1="792" y2="792"/>
<path d="M 80 792 A 4 4 0 0 0 84 788" fill="none"/>
</g>
<g>
<line x1="84" x2="84" y1="188" y2="200"/>
<line x1="84" x2="84" y1="200" y2="212"/>
<line marker-end="url(#triangle)" x1="84" x2="124" y1="200" y2="200"/>
</g>
<g>
<line x1="84" x2="84" y1="748" y2="760"/>
<line x1="84" x2="84" y1="760" y2="788"/>
<line marker-end="url(#triangle)" x1="84" x2="124" y1="760" y2="760"/>
</g>
<g>
<line x1="108" x2="108" y1="124" y2="192"/>
<path d="M 112 120 A 4 4 0 0 0 108 124" fill="none"/>
</g>
<g>
<line x1="108" x2="108" y1="208" y2="436"/>
<path d="M 108 436 A 4 4 0 0 0 112 440" fill="none"/>
</g>
<g>
<line x1="108" x2="108" y1="700" y2="752"/>
<path d="M 112 696 A 4 4 0 0 0 108 700" fill="none"/>
</g>
<g>
<line x1="108" x2="108" y1="768" y2="836"/>
<path d="M 108 836 A 4 4 0 0 0 112 840" fill="none"/>
</g>
<g>
<line x1="112" x2="392" y1="120" y2="120"/>
<path d="M 396 124 A 4 4 0 0 0 392 120" fill="none"/>
</g>
<g>
<line x1="112" x2="392" y1="440" y2="440"/>
<path d="M 392 440 A 4 4 0 0 0 396 436" fill="none"/>
</g>
<g>
<line x1="112" x2="392" y1="696" y2="696"/>
<path d="M 396 700 A 4 4 0 0 0 392 696" fill="none"/>
</g>
<g>
<line x1="112" x2="392" y1="840" y2="840"/>
<path d="M 392 840 A 4 4 0 0 0 396 836" fill="none"/>
</g>
<g>
<line x1="132" x2="132" y1="172" y2="212"/>
<path d="M 132 212 A 4 4 0 0 0 136 216" fill="none"/>
<path d="M 136 168 A 4 4 0 0 0 132 172" fill="none"/>
</g>
<g>
<line x1="132" x2="132" y1="268" y2="308"/>
<path d="M 132 308 A 4 4 0 0 0 136 312" fill="none"/>
<path d="M 136 264 A 4 4 0 0 0 132 268" fill="none"/>
</g>
<g>
<line x1="132" x2="132" y1="748" y2="788"/>
<path d="M 132 788 A 4 4 0 0 0 136 792" fill="none"/>
<path d="M 136 744 A 4 4 0 0 0 132 748" fill="none"/>
</g>
<g>
<line x1="136" x2="224" y1="168" y2="168"/>
<path d="M 228 172 A 4 4 0 0 0 224 168" fill="none"/>
</g>
<g>
<line x1="136" x2="164" y1="216" y2="216"/>
<line marker-end="url(#triangle)" x1="164" x2="164" y1="216" y2="252"/>
<line x1="164" x2="224" y1="216" y2="216"/>
<path d="M 224 216 A 4 4 0 0 0 228 212" fill="none"/>
</g>
<g>
<line x1="136" x2="224" y1="264" y2="264"/>
<path d="M 228 268 A 4 4 0 0 0 224 264" fill="none"/>
</g>
<g>
<line x1="136" x2="224" y1="312" y2="312"/>
<path d="M 224 312 A 4 4 0 0 0 228 308" fill="none"/>
</g>
<g>
<line x1="136" x2="224" y1="744" y2="744"/>
<path d="M 228 748 A 4 4 0 0 0 224 744" fill="none"/>
</g>
<g>
<line x1="136" x2="224" y1="792" y2="792"/>
<path d="M 224 792 A 4 4 0 0 0 228 788" fill="none"/>
</g>
<g>
<line x1="228" x2="228" y1="172" y2="212"/>
</g>
<g>
<line x1="228" x2="228" y1="268" y2="308"/>
</g>
<g>
<line x1="228" x2="228" y1="748" y2="760"/>
<line x1="228" x2="228" y1="760" y2="788"/>
<line marker-end="url(#triangle)" x1="228" x2="260" y1="760" y2="760"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="240" x2="236" y1="280" y2="280"/>
<line marker-end="url(#triangle)" x1="240" x2="260" y1="280" y2="280"/>
</g>
<g>
<line x1="268" x2="268" y1="28" y2="68"/>
<path d="M 268 68 A 4 4 0 0 0 272 72" fill="none"/>
<path d="M 272 24 A 4 4 0 0 0 268 28" fill="none"/>
</g>
<g>
<line x1="268" x2="268" y1="172" y2="212"/>
<path d="M 268 212 A 4 4 0 0 0 272 216" fill="none"/>
<path d="M 272 168 A 4 4 0 0 0 268 172" fill="none"/>
</g>
<g>
<line x1="268" x2="268" y1="268" y2="308"/>
<path d="M 268 308 A 4 4 0 0 0 272 312" fill="none"/>
<path d="M 272 264 A 4 4 0 0 0 268 268" fill="none"/>
</g>
<g>
<line x1="268" x2="268" y1="364" y2="404"/>
<path d="M 268 404 A 4 4 0 0 0 272 408" fill="none"/>
<path d="M 272 360 A 4 4 0 0 0 268 364" fill="none"/>
</g>
<g>
<line x1="268" x2="268" y1="492" y2="532"/>
<path d="M 268 532 A 4 4 0 0 0 272 536" fill="none"/>
<path d="M 272 488 A 4 4 0 0 0 268 492" fill="none"/>
</g>
<g>
<line x1="268" x2="268" y1="604" y2="644"/>
<path d="M 268 644 A 4 4 0 0 0 272 648" fill="none"/>
<path d="M 272 600 A 4 4 0 0 0 268 604" fill="none"/>
</g>
<g>
<line x1="268" x2="268" y1="748" y2="788"/>
<path d="M 268 788 A 4 4 0 0 0 272 792" fill="none"/>
<path d="M 272 744 A 4 4 0 0 0 268 748" fill="none"/>
</g>
<g>
<line x1="268" x2="268" y1="892" y2="932"/>
<path d="M 268 932 A 4 4 0 0 0 272 936" fill="none"/>
<path d="M 272 888 A 4 4 0 0 0 268 892" fill="none"/>
</g>
<g>
<line x1="272" x2="368" y1="24" y2="24"/>
<path d="M 372 28 A 4 4 0 0 0 368 24" fill="none"/>
</g>
<g>
<line x1="272" x2="308" y1="72" y2="72"/>
<line x1="308" x2="308" y1="72" y2="112"/>
<line x1="308" x2="368" y1="72" y2="72"/>
<path d="M 368 72 A 4 4 0 0 0 372 68" fill="none"/>
</g>
<g>
<line x1="272" x2="368" y1="168" y2="168"/>
<path d="M 372 172 A 4 4 0 0 0 368 168" fill="none"/>
</g>
<g>
<line x1="272" x2="308" y1="216" y2="216"/>
<line marker-end="url(#triangle)" x1="308" x2="308" y1="216" y2="252"/>
<line x1="308" x2="368" y1="216" y2="216"/>
<path d="M 368 216 A 4 4 0 0 0 372 212" fill="none"/>
</g>
<g>
<line x1="272" x2="368" y1="264" y2="264"/>
<path d="M 372 268 A 4 4 0 0 0 368 264" fill="none"/>
</g>
<g>
<line x1="272" x2="308" y1="312" y2="312"/>
<line marker-end="url(#triangle)" x1="308" x2="308" y1="312" y2="348"/>
<line x1="308" x2="368" y1="312" y2="312"/>
<path d="M 368 312 A 4 4 0 0 0 372 308" fill="none"/>
</g>
<g>
<line x1="272" x2="368" y1="360" y2="360"/>
<path d="M 372 364 A 4 4 0 0 0 368 360" fill="none"/>
</g>
<g>
<line x1="272" x2="308" y1="408" y2="408"/>
<line x1="308" x2="308" y1="408" y2="432"/>
<line x1="308" x2="368" y1="408" y2="408"/>
<path d="M 368 408 A 4 4 0 0 0 372 404" fill="none"/>
</g>
<g>
<line x1="272" x2="368" y1="488" y2="488"/>
<path d="M 372 492 A 4 4 0 0 0 368 488" fill="none"/>
</g>
<g>
<line x1="272" x2="368" y1="536" y2="536"/>
<path d="M 368 536 A 4 4 0 0 0 372 532" fill="none"/>
</g>
<g>
<line x1="272" x2="368" y1="600" y2="600"/>
<path d="M 372 604 A 4 4 0 0 0 368 600" fill="none"/>
</g>
<g>
<line x1="272" x2="332" y1="648" y2="648"/>
<line x1="332" x2="332" y1="648" y2="688"/>
<line x1="332" x2="368" y1="648" y2="648"/>
<path d="M 368 648 A 4 4 0 0 0 372 644" fill="none"/>
</g>
<g>
<line x1="272" x2="300" y1="744" y2="744"/>
<line x1="300" x2="300" y1="704" y2="744"/>
<line x1="300" x2="368" y1="744" y2="744"/>
<path d="M 372 748 A 4 4 0 0 0 368 744" fill="none"/>
</g>
<g>
<line x1="272" x2="316" y1="792" y2="792"/>
<line x1="316" x2="316" y1="792" y2="832"/>
<line x1="316" x2="368" y1="792" y2="792"/>
<path d="M 368 792 A 4 4 0 0 0 372 788" fill="none"/>
</g>
<g>
<line x1="272" x2="368" y1="888" y2="888"/>
<path d="M 372 892 A 4 4 0 0 0 368 888" fill="none"/>
</g>
<g>
<line x1="272" x2="368" y1="936" y2="936"/>
<path d="M 368 936 A 4 4 0 0 0 372 932" fill="none"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="300" x2="300" y1="672" y2="660"/>
<line x1="300" x2="300" y1="672" y2="688"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="308" x2="308" y1="128" y2="156"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="308" x2="308" y1="448" y2="476"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="316" x2="316" y1="848" y2="876"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="332" x2="332" y1="704" y2="732"/>
</g>
<g>
<line x1="372" x2="372" y1="28" y2="68"/>
</g>
<g>
<line x1="372" x2="372" y1="172" y2="212"/>
</g>
<g>
<line x1="372" x2="372" y1="268" y2="308"/>
</g>
<g>
<line x1="372" x2="372" y1="364" y2="404"/>
</g>
<g>
<line x1="372" x2="372" y1="492" y2="532"/>
</g>
<g>
<line x1="372" x2="372" y1="604" y2="644"/>
</g>
<g>
<line x1="372" x2="372" y1="748" y2="788"/>
</g>
<g>
<line x1="372" x2="372" y1="892" y2="932"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="384" x2="380" y1="760" y2="760"/>
<line marker-end="url(#triangle)" x1="384" x2="412" y1="760" y2="760"/>
</g>
<g>
<line x1="396" x2="396" y1="124" y2="436"/>
</g>
<g>
<line x1="396" x2="396" y1="700" y2="752"/>
</g>
<g>
<line x1="396" x2="396" y1="768" y2="836"/>
</g>
<g>
<line x1="420" x2="420" y1="748" y2="788"/>
<path d="M 420 788 A 4 4 0 0 0 424 792" fill="none"/>
<path d="M 424 744 A 4 4 0 0 0 420 748" fill="none"/>
</g>
<g>
<line x1="424" x2="520" y1="744" y2="744"/>
<path d="M 524 748 A 4 4 0 0 0 520 744" fill="none"/>
</g>
<g>
<line x1="424" x2="520" y1="792" y2="792"/>
<path d="M 520 792 A 4 4 0 0 0 524 788" fill="none"/>
</g>
<g>
<line x1="524" x2="524" y1="748" y2="788"/>
</g>
<g>
<text x="25" y="204">
Client
</text>
</g>
<g>
<text x="33" y="764">
Fetch
</text>
</g>
<g>
<text x="33" y="780">
Stage
</text>
</g>
<g>
<text x="121" y="140">
Validator
</text>
</g>
<g>
<text x="121" y="716">
TPU
</text>
</g>
<g>
<text x="145" y="188">
Fetch
</text>
</g>
<g>
<text x="145" y="204">
Stage
</text>
</g>
<g>
<text x="145" y="284">
TPU
</text>
</g>
<g>
<text x="145" y="764">
SigVerify
</text>
</g>
<g>
<text x="145" y="780">
Stage
</text>
</g>
<g>
<text x="281" y="44">
Upstream
</text>
</g>
<g>
<text x="281" y="60">
Validators
</text>
</g>
<g>
<text x="281" y="188">
Repair
</text>
</g>
<g>
<text x="281" y="204">
Stage
</text>
</g>
<g>
<text x="281" y="284">
Blockstore
</text>
</g>
<g>
<text x="281" y="380">
Multicast
</text>
</g>
<g>
<text x="281" y="396">
Stage
</text>
</g>
<g>
<text x="281" y="508">
Downstream
</text>
</g>
<g>
<text x="281" y="524">
Validators
</text>
</g>
<g>
<text x="281" y="620">
PoH
</text>
</g>
<g>
<text x="281" y="636">
Service
</text>
</g>
<g>
<text x="281" y="764">
Banking
</text>
</g>
<g>
<text x="281" y="780">
Stage
</text>
</g>
<g>
<text x="281" y="908">
Banktree
</text>
</g>
<g>
<text x="433" y="764">
Blockstore
</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -0,0 +1,456 @@
<svg class="bob" font-family="arial" font-size="14" height="480" width="592" xmlns="http://www.w3.org/2000/svg">
<defs>
<marker id="triangle" markerHeight="8" markerWidth="8" orient="auto" refX="4" refY="2" viewBox="0 0 8 4">
<polygon fill="black" points="0,0 0,4 8,2 0,0"/>
</marker>
<marker id="clear_triangle" markerHeight="10" markerWidth="10" orient="auto" refX="1" refY="7" viewBox="0 0 20 14">
<polygon fill="none" points="2,2 2,12 18,7 2,2" stroke="black" stroke-width="2"/>
</marker>
<marker id="circle" markerHeight="5" markerWidth="5" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<circle cx="10" cy="10" fill="black" r="8"/>
</marker>
<marker id="square" markerHeight="5" markerWidth="5" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<rect fill="black" height="20" width="20" x="0" y="0"/>
</marker>
<marker id="open_circle" markerHeight="10" markerWidth="10" orient="auto" refX="10" refY="10" viewBox="0 0 20 20">
<circle cx="10" cy="10" fill="white" r="4" stroke="black" stroke-width="2"/>
</marker>
<marker id="big_open_circle" markerHeight="20" markerWidth="20" orient="auto" refX="20" refY="20" viewBox="0 0 40 40">
<circle cx="20" cy="20" fill="white" r="6" stroke="black" stroke-width="2"/>
</marker>
</defs>
<style type="text/css">
line,path {
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
line.dashed {
stroke-dasharray: 5;
}
circle.solid {
fill:black;
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
circle.open {
fill:none;
stroke: black;
stroke-width: 2;
stroke-opacity: 1;
fill-opacity: 1;
stroke-linecap: round;
stroke-linejoin: miter;
}
tspan.head{
fill: none;
stroke: none;
}
</style>
<rect fill="white" height="480" width="592" x="0" y="0"/>
<g>
<line x1="12" x2="12" y1="60" y2="116"/>
<path d="M 12 116 A 4 4 0 0 0 16 120" fill="none"/>
<path d="M 16 56 A 4 4 0 0 0 12 60" fill="none"/>
</g>
<g>
<line x1="16" x2="80" y1="56" y2="56"/>
<path d="M 84 60 A 4 4 0 0 0 80 56" fill="none"/>
</g>
<g>
<line x1="16" x2="52" y1="120" y2="120"/>
<line x1="52" x2="52" y1="120" y2="420"/>
<line x1="52" x2="80" y1="120" y2="120"/>
<path d="M 52 420 A 4 4 0 0 0 56 424" fill="none"/>
<path d="M 80 120 A 4 4 0 0 0 84 116" fill="none"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="56" x2="124" y1="424" y2="424"/>
</g>
<g>
<line x1="84" x2="84" y1="60" y2="116"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="84" x2="124" y1="72" y2="72"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="96" x2="92" y1="104" y2="104"/>
<line x1="96" x2="132" y1="104" y2="104"/>
</g>
<g>
<line x1="108" x2="108" y1="12" y2="64"/>
<path d="M 112 8 A 4 4 0 0 0 108 12" fill="none"/>
</g>
<g>
<line x1="108" x2="108" y1="80" y2="96"/>
</g>
<g>
<line x1="108" x2="108" y1="112" y2="416"/>
</g>
<g>
<line x1="108" x2="108" y1="432" y2="468"/>
<path d="M 108 468 A 4 4 0 0 0 112 472" fill="none"/>
</g>
<g>
<line x1="112" x2="416" y1="8" y2="8"/>
<path d="M 420 12 A 4 4 0 0 0 416 8" fill="none"/>
</g>
<g>
<line x1="112" x2="416" y1="472" y2="472"/>
<path d="M 416 472 A 4 4 0 0 0 420 468" fill="none"/>
</g>
<g>
<line x1="124" x2="124" y1="236" y2="276"/>
<path d="M 124 276 A 4 4 0 0 0 128 280" fill="none"/>
<path d="M 128 232 A 4 4 0 0 0 124 236" fill="none"/>
</g>
<g>
<line x1="128" x2="156" y1="232" y2="232"/>
<line x1="156" x2="156" y1="144" y2="232"/>
<line x1="156" x2="184" y1="232" y2="232"/>
<path d="M 188 236 A 4 4 0 0 0 184 232" fill="none"/>
</g>
<g>
<line x1="128" x2="184" y1="280" y2="280"/>
<path d="M 184 280 A 4 4 0 0 0 188 276" fill="none"/>
</g>
<g>
<line x1="132" x2="132" y1="60" y2="116"/>
<path d="M 132 116 A 4 4 0 0 0 136 120" fill="none"/>
<path d="M 136 56 A 4 4 0 0 0 132 60" fill="none"/>
</g>
<g>
<line x1="132" x2="132" y1="412" y2="436"/>
<path d="M 132 436 A 4 4 0 0 0 136 440" fill="none"/>
<path d="M 136 408 A 4 4 0 0 0 132 412" fill="none"/>
</g>
<g>
<line x1="136" x2="288" y1="56" y2="56"/>
<path d="M 292 60 A 4 4 0 0 0 288 56" fill="none"/>
</g>
<g>
<line x1="136" x2="288" y1="120" y2="120"/>
<path d="M 288 120 A 4 4 0 0 0 292 116" fill="none"/>
</g>
<g>
<line x1="136" x2="156" y1="408" y2="408"/>
<line x1="156" x2="156" y1="304" y2="408"/>
<line x1="156" x2="176" y1="408" y2="408"/>
<path d="M 180 412 A 4 4 0 0 0 176 408" fill="none"/>
</g>
<g>
<line x1="136" x2="176" y1="440" y2="440"/>
<path d="M 176 440 A 4 4 0 0 0 180 436" fill="none"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="156" x2="156" y1="144" y2="132"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="156" x2="156" y1="304" y2="292"/>
</g>
<g>
<line x1="180" x2="180" y1="412" y2="424"/>
<line x1="180" x2="180" y1="424" y2="436"/>
<line marker-end="url(#triangle)" x1="180" x2="220" y1="424" y2="424"/>
</g>
<g>
<line x1="188" x2="188" y1="236" y2="276"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="200" x2="196" y1="248" y2="248"/>
<line x1="200" x2="212" y1="248" y2="248"/>
<line x1="212" x2="212" y1="236" y2="248"/>
<line x1="212" x2="212" y1="248" y2="276"/>
<path d="M 212 276 A 4 4 0 0 0 216 280" fill="none"/>
<path d="M 216 232 A 4 4 0 0 0 212 236" fill="none"/>
</g>
<g>
<line x1="204" x2="204" y1="156" y2="180"/>
<path d="M 204 180 A 4 4 0 0 0 208 184" fill="none"/>
<path d="M 208 152 A 4 4 0 0 0 204 156" fill="none"/>
</g>
<g>
<line x1="208" x2="336" y1="152" y2="152"/>
<path d="M 340 156 A 4 4 0 0 0 336 152" fill="none"/>
</g>
<g>
<line x1="208" x2="336" y1="184" y2="184"/>
<path d="M 336 184 A 4 4 0 0 0 340 180" fill="none"/>
</g>
<g>
<line x1="216" x2="252" y1="232" y2="232"/>
<line x1="252" x2="252" y1="208" y2="232"/>
<line x1="252" x2="280" y1="232" y2="232"/>
<path d="M 284 236 A 4 4 0 0 0 280 232" fill="none"/>
</g>
<g>
<line x1="216" x2="280" y1="280" y2="280"/>
<path d="M 280 280 A 4 4 0 0 0 284 276" fill="none"/>
</g>
<g>
<line x1="228" x2="228" y1="412" y2="452"/>
<path d="M 228 452 A 4 4 0 0 0 232 456" fill="none"/>
<path d="M 232 408 A 4 4 0 0 0 228 412" fill="none"/>
</g>
<g>
<line x1="232" x2="292" y1="408" y2="408"/>
<line x1="292" x2="292" y1="384" y2="408"/>
<line x1="292" x2="320" y1="408" y2="408"/>
<path d="M 324 412 A 4 4 0 0 0 320 408" fill="none"/>
</g>
<g>
<line x1="232" x2="320" y1="456" y2="456"/>
<path d="M 320 456 A 4 4 0 0 0 324 452" fill="none"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="252" x2="252" y1="208" y2="196"/>
</g>
<g>
<line x1="252" x2="252" y1="332" y2="356"/>
<path d="M 252 356 A 4 4 0 0 0 256 360" fill="none"/>
<path d="M 256 328 A 4 4 0 0 0 252 332" fill="none"/>
</g>
<g>
<line x1="256" x2="276" y1="328" y2="328"/>
<line x1="276" x2="276" y1="304" y2="328"/>
<line x1="276" x2="344" y1="328" y2="328"/>
<path d="M 348 332 A 4 4 0 0 0 344 328" fill="none"/>
</g>
<g>
<line x1="256" x2="344" y1="360" y2="360"/>
<path d="M 344 360 A 4 4 0 0 0 348 356" fill="none"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="276" x2="276" y1="304" y2="292"/>
</g>
<g>
<line x1="284" x2="284" y1="236" y2="276"/>
</g>
<g>
<line x1="292" x2="292" y1="60" y2="116"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="292" x2="292" y1="384" y2="372"/>
</g>
<g>
<line x1="300" x2="300" y1="236" y2="276"/>
<path d="M 300 276 A 4 4 0 0 0 304 280" fill="none"/>
<path d="M 304 232 A 4 4 0 0 0 300 236" fill="none"/>
</g>
<g>
<line x1="304" x2="392" y1="232" y2="232"/>
<path d="M 396 236 A 4 4 0 0 0 392 232" fill="none"/>
</g>
<g>
<line x1="304" x2="324" y1="280" y2="280"/>
<line marker-end="url(#triangle)" x1="324" x2="324" y1="280" y2="316"/>
<line x1="324" x2="392" y1="280" y2="280"/>
<path d="M 392 280 A 4 4 0 0 0 396 276" fill="none"/>
</g>
<g>
<line x1="324" x2="324" y1="412" y2="424"/>
<line x1="324" x2="324" y1="424" y2="452"/>
<line marker-end="url(#triangle)" x1="324" x2="452" y1="424" y2="424"/>
</g>
<g>
<line x1="340" x2="340" y1="156" y2="180"/>
</g>
<g>
<line x1="348" x2="348" y1="332" y2="356"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="352" x2="348" y1="168" y2="168"/>
<line x1="352" x2="436" y1="168" y2="168"/>
</g>
<g>
<line x1="396" x2="396" y1="236" y2="276"/>
</g>
<g>
<line marker-end="url(#triangle)" x1="408" x2="404" y1="248" y2="248"/>
<line x1="408" x2="460" y1="248" y2="248"/>
<line x1="460" x2="460" y1="220" y2="248"/>
<line x1="460" x2="460" y1="248" y2="292"/>
<path d="M 460 292 A 4 4 0 0 0 464 296" fill="none"/>
<path d="M 464 216 A 4 4 0 0 0 460 220" fill="none"/>
</g>
<g>
<line x1="420" x2="420" y1="12" y2="160"/>
</g>
<g>
<line x1="420" x2="420" y1="176" y2="240"/>
</g>
<g>
<line x1="420" x2="420" y1="256" y2="416"/>
</g>
<g>
<line x1="420" x2="420" y1="432" y2="468"/>
</g>
<g>
<line x1="436" x2="436" y1="156" y2="240"/>
<path d="M 440 152 A 4 4 0 0 0 436 156" fill="none"/>
</g>
<g>
<line x1="436" x2="436" y1="256" y2="416"/>
</g>
<g>
<line x1="436" x2="436" y1="432" y2="452"/>
<path d="M 436 452 A 4 4 0 0 0 440 456" fill="none"/>
</g>
<g>
<line x1="440" x2="584" y1="152" y2="152"/>
<path d="M 588 156 A 4 4 0 0 0 584 152" fill="none"/>
</g>
<g>
<line x1="440" x2="584" y1="456" y2="456"/>
<path d="M 584 456 A 4 4 0 0 0 588 452" fill="none"/>
</g>
<g>
<line x1="460" x2="460" y1="364" y2="436"/>
<path d="M 460 436 A 4 4 0 0 0 464 440" fill="none"/>
<path d="M 464 360 A 4 4 0 0 0 460 364" fill="none"/>
</g>
<g>
<line x1="464" x2="560" y1="216" y2="216"/>
<path d="M 564 220 A 4 4 0 0 0 560 216" fill="none"/>
</g>
<g>
<line x1="464" x2="560" y1="296" y2="296"/>
<path d="M 560 296 A 4 4 0 0 0 564 292" fill="none"/>
</g>
<g>
<line x1="464" x2="560" y1="360" y2="360"/>
<path d="M 564 364 A 4 4 0 0 0 560 360" fill="none"/>
</g>
<g>
<line x1="464" x2="560" y1="440" y2="440"/>
<path d="M 560 440 A 4 4 0 0 0 564 436" fill="none"/>
</g>
<g>
<line x1="564" x2="564" y1="220" y2="292"/>
</g>
<g>
<line x1="564" x2="564" y1="364" y2="436"/>
</g>
<g>
<line x1="588" x2="588" y1="156" y2="452"/>
</g>
<g>
<text x="25" y="92">
Client
</text>
</g>
<g>
<text x="129" y="28">
Validator
</text>
</g>
<g>
<text x="137" y="252">
Bank
</text>
</g>
<g>
<text x="137" y="268">
Forks
</text>
</g>
<g>
<text x="145" y="92">
JSON
</text>
</g>
<g>
<text x="145" y="428">
TPU
</text>
</g>
<g>
<text x="185" y="92">
RPC
</text>
</g>
<g>
<text x="217" y="92">
Service
</text>
</g>
<g>
<text x="217" y="172">
Gossip
</text>
</g>
<g>
<text x="225" y="252">
Replay
</text>
</g>
<g>
<text x="225" y="268">
Stage
</text>
</g>
<g>
<text x="241" y="428">
Broadcast
</text>
</g>
<g>
<text x="241" y="444">
Stage
</text>
</g>
<g>
<text x="265" y="348">
Blocktree
</text>
</g>
<g>
<text x="273" y="172">
Service
</text>
</g>
<g>
<text x="313" y="252">
BlobFetch
</text>
</g>
<g>
<text x="321" y="268">
Stage
</text>
</g>
<g>
<text x="449" y="172">
Validators
</text>
</g>
<g>
<text x="473" y="252">
Upstream
</text>
</g>
<g>
<text x="473" y="268">
Validators
</text>
</g>
<g>
<text x="473" y="396">
Downstream
</text>
</g>
<g>
<text x="473" y="412">
Validators
</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

81
book/src/SUMMARY.md Normal file
View File

@@ -0,0 +1,81 @@
# Table of contents
* [Introduction](introduction.md)
* [Terminology](terminology.md)
* [Getting Started](getting-started/README.md)
* [Testnet Participation](getting-started/testnet-participation.md)
* [Example Client: Web Wallet](getting-started/webwallet.md)
* [Programming Model](programs/README.md)
* [Example: Tic-Tac-Toe](programs/tictactoe.md)
* [Drones](programs/drones.md)
* [A Solana Cluster](cluster/README.md)
* [Synchronization](cluster/synchronization.md)
* [Leader Rotation](cluster/leader-rotation.md)
* [Fork Generation](cluster/fork-generation.md)
* [Managing Forks](cluster/managing-forks.md)
* [Turbine Block Propagation](cluster/turbine-block-propagation.md)
* [Ledger Replication](cluster/ledger-replication.md)
* [Secure Vote Signing](cluster/vote-signing.md)
* [Stake Delegation and Rewards](cluster/stake-delegation-and-rewards.md)
* [Performance Metrics](cluster/performance-metrics.md)
* [Anatomy of a Validator](validator/README.md)
* [TPU](validator/tpu.md)
* [TVU](validator/tvu/README.md)
* [Blocktree](validator/tvu/blocktree.md)
* [Gossip Service](validator/gossip.md)
* [The Runtime](validator/runtime.md)
* [Anatomy of a Transaction](transaction.md)
* [Running a Validator](running-validator/README.md)
* [Hardware Requirements](running-validator/validator-hardware.md)
* [Choosing a Testnet](running-validator/validator-testnet.md)
* [Installing the Validator Software](running-validator/validator-software.md)
* [Starting a Validator](running-validator/validator-start.md)
* [Staking](running-validator/validator-stake.md)
* [Monitoring a Validator](running-validator/validator-monitor.md)
* [Publishing Validator Info](running-validator/validator-info.md)
* [Troubleshooting](running-validator/validator-troubleshoot.md)
* [FAQ](running-validator/validator-faq.md)
* [Running a Replicator](running-replicator.md)
* [API Reference](api-reference/README.md)
* [Transaction](api-reference/transaction-api.md)
* [Instruction](api-reference/instruction-api.md)
* [Blockstreamer](api-reference/blockstreamer.md)
* [JSON RPC API](api-reference/jsonrpc-api.md)
* [JavaScript API](api-reference/javascript-api.md)
* [solana CLI](api-reference/cli.md)
* [Accepted Design Proposals](proposals/README.md)
* [Ledger Replication](proposals/ledger-replication-to-implement.md)
* [Secure Vote Signing](proposals/vote-signing-to-implement.md)
* [Staking Rewards](proposals/staking-rewards.md)
* [Cluster Economics](proposals/ed_overview/README.md)
* [Validation-client Economics](proposals/ed_overview/ed_validation_client_economics/README.md)
* [State-validation Protocol-based Rewards](proposals/ed_overview/ed_validation_client_economics/ed_vce_state_validation_protocol_based_rewards.md)
* [State-validation Transaction Fees](proposals/ed_overview/ed_validation_client_economics/ed_vce_state_validation_transaction_fees.md)
* [Replication-validation Transaction Fees](proposals/ed_overview/ed_validation_client_economics/ed_vce_replication_validation_transaction_fees.md)
* [Validation Stake Delegation](proposals/ed_overview/ed_validation_client_economics/ed_vce_validation_stake_delegation.md)
* [Replication-client Economics](proposals/ed_overview/ed_replication_client_economics/README.md)
* [Storage-replication Rewards](proposals/ed_overview/ed_replication_client_economics/ed_rce_storage_replication_rewards.md)
* [Replication-client Reward Auto-delegation](proposals/ed_overview/ed_replication_client_economics/ed_rce_replication_client_reward_auto_delegation.md)
* [Economic Sustainability](proposals/ed_overview/ed_economic_sustainability.md)
* [Attack Vectors](proposals/ed_overview/ed_attack_vectors.md)
* [Economic Design MVP](proposals/ed_overview/ed_mvp.md)
* [References](proposals/ed_overview/ed_references.md)
* [Cluster Test Framework](proposals/cluster-test-framework.md)
* [Validator](proposals/validator-proposal.md)
* [Simple Payment and State Verification](proposals/simple-payment-and-state-verification.md)
* [Cross-Program Invocation](proposals/cross-program-invocation.md)
* [Implemented Design Proposals](implemented-proposals/README.md)
* [Blocktree](implemented-proposals/blocktree.md)
* [Cluster Software Installation and Updates](implemented-proposals/installer.md)
* [Deterministic Transaction Fees](implemented-proposals/transaction-fees.md)
* [Tower BFT](implemented-proposals/tower-bft.md)
* [Leader-to-Leader Transition](implemented-proposals/leader-leader-transition.md)
* [Leader-to-Validator Transition](implemented-proposals/leader-validator-transition.md)
* [Passive Stake Delegation and Rewards](implemented-proposals/passive-stake-delegation-and-rewards.md)
* [Persistent Account Storage](implemented-proposals/persistent-account-storage.md)
* [Reliable Vote Transmission](implemented-proposals/reliable-vote-transmission.md)
* [Repair Service](implemented-proposals/repair-service.md)
* [Testing Programs](implemented-proposals/testing-programs.md)
* [Credit-only Accounts](implemented-proposals/credit-only-credit-debit-accounts.md)
* [Embedding the Move Langauge](implemented-proposals/embedding-move.md)

View File

@@ -0,0 +1,4 @@
# API Reference
The following sections contain API references material you may find useful
when developing applications utilizing a Solana cluster.

View File

@@ -0,0 +1,4 @@
# API Reference
The following sections contain API references material you may find useful when developing applications utilizing a Solana cluster.

View File

@@ -0,0 +1,28 @@
# Blockstreamer
Solana supports a node type called an _blockstreamer_. This fullnode variation is intended for applications that need to observe the data plane without participating in transaction validation or ledger replication.
A blockstreamer runs without a vote signer, and can optionally stream ledger entries out to a Unix domain socket as they are processed. The JSON-RPC service still functions as on any other node.
To run a blockstreamer, include the argument `no-signer` and \(optional\) `blockstream` socket location:
```bash
$ ./multinode-demo/validator-x.sh --no-signer --blockstream <SOCKET>
```
The stream will output a series of JSON objects:
* An Entry event JSON object is sent when each ledger entry is processed, with the following fields:
* `dt`, the system datetime, as RFC3339-formatted string
* `t`, the event type, always "entry"
* `s`, the slot height, as unsigned 64-bit integer
* `h`, the tick height, as unsigned 64-bit integer
* `entry`, the entry, as JSON object
* A Block event JSON object is sent when a block is complete, with the following fields:
* `dt`, the system datetime, as RFC3339-formatted string
* `t`, the event type, always "block"
* `s`, the slot height, as unsigned 64-bit integer
* `h`, the tick height, as unsigned 64-bit integer
* `l`, the slot leader id, as base-58 encoded string
* `id`, the block id, as base-58 encoded string

View File

@@ -0,0 +1,370 @@
# solana CLI
The [solana-cli crate](https://crates.io/crates/solana-cli) provides a command-line interface tool for Solana
## Examples
### Get Pubkey
```bash
// Command
$ solana address
// Return
<PUBKEY>
```
### Airdrop Lamports
```bash
// Command
$ solana airdrop 123
// Return
"Your balance is: 123"
```
### Get Balance
```bash
// Command
$ solana balance
// Return
"Your balance is: 123"
```
### Confirm Transaction
```bash
// Command
$ solana confirm <TX_SIGNATURE>
// Return
"Confirmed" / "Not found" / "Transaction failed with error <ERR>"
```
### Deploy program
```bash
// Command
$ solana deploy <PATH>
// Return
<PROGRAM_ID>
```
### Unconditional Immediate Transfer
```bash
// Command
$ solana pay <PUBKEY> 123
// Return
<TX_SIGNATURE>
```
### Post-Dated Transfer
```bash
// Command
$ solana pay <PUBKEY> 123 \
--after 2018-12-24T23:59:00 --require-timestamp-from <PUBKEY>
// Return
{signature: <TX_SIGNATURE>, processId: <PROCESS_ID>}
```
_`require-timestamp-from` is optional. If not provided, the transaction will expect a timestamp signed by this wallet's secret key_
### Authorized Transfer
A third party must send a signature to unlock the lamports.
```bash
// Command
$ solana pay <PUBKEY> 123 \
--require-signature-from <PUBKEY>
// Return
{signature: <TX_SIGNATURE>, processId: <PROCESS_ID>}
```
### Post-Dated and Authorized Transfer
```bash
// Command
$ solana pay <PUBKEY> 123 \
--after 2018-12-24T23:59 --require-timestamp-from <PUBKEY> \
--require-signature-from <PUBKEY>
// Return
{signature: <TX_SIGNATURE>, processId: <PROCESS_ID>}
```
### Multiple Witnesses
```bash
// Command
$ solana pay <PUBKEY> 123 \
--require-signature-from <PUBKEY> \
--require-signature-from <PUBKEY>
// Return
{signature: <TX_SIGNATURE>, processId: <PROCESS_ID>}
```
### Cancelable Transfer
```bash
// Command
$ solana pay <PUBKEY> 123 \
--require-signature-from <PUBKEY> \
--cancelable
// Return
{signature: <TX_SIGNATURE>, processId: <PROCESS_ID>}
```
### Cancel Transfer
```bash
// Command
$ solana cancel <PROCESS_ID>
// Return
<TX_SIGNATURE>
```
### Send Signature
```bash
// Command
$ solana send-signature <PUBKEY> <PROCESS_ID>
// Return
<TX_SIGNATURE>
```
### Indicate Elapsed Time
Use the current system time:
```bash
// Command
$ solana send-timestamp <PUBKEY> <PROCESS_ID>
// Return
<TX_SIGNATURE>
```
Or specify some other arbitrary timestamp:
```bash
// Command
$ solana send-timestamp <PUBKEY> <PROCESS_ID> --date 2018-12-24T23:59:00
// Return
<TX_SIGNATURE>
```
## Usage
```text
solana 0.12.0
USAGE:
solana [FLAGS] [OPTIONS] [SUBCOMMAND]
FLAGS:
-h, --help Prints help information
--rpc-tls Enable TLS for the RPC endpoint
-V, --version Prints version information
OPTIONS:
--drone-host <IP ADDRESS> Drone host to use [default: same as --host]
--drone-port <PORT> Drone port to use [default: 9900]
-n, --host <IP ADDRESS> Host to use for both RPC and drone [default: 127.0.0.1]
-k, --keypair <PATH> /path/to/id.json
--rpc-host <IP ADDRESS> RPC host to use [default: same as --host]
--rpc-port <PORT> RPC port to use [default: 8899]
SUBCOMMANDS:
address Get your public key
airdrop Request a batch of lamports
balance Get your balance
cancel Cancel a transfer
confirm Confirm transaction by signature
deploy Deploy a program
get-transaction-count Get current transaction count
help Prints this message or the help of the given subcommand(s)
pay Send a payment
send-signature Send a signature to authorize a transfer
send-timestamp Send a timestamp to unlock a transfer
```
```text
solana-address
Get your public key
USAGE:
solana address
FLAGS:
-h, --help Prints help information
-V, --version Prints version information
```
```text
solana-airdrop
Request a batch of lamports
USAGE:
solana airdrop <NUM>
FLAGS:
-h, --help Prints help information
-V, --version Prints version information
ARGS:
<NUM> The number of lamports to request
```
```text
solana-balance
Get your balance
USAGE:
solana balance
FLAGS:
-h, --help Prints help information
-V, --version Prints version information
```
```text
solana-cancel
Cancel a transfer
USAGE:
solana cancel <PROCESS_ID>
FLAGS:
-h, --help Prints help information
-V, --version Prints version information
ARGS:
<PROCESS_ID> The process id of the transfer to cancel
```
```text
solana-confirm
Confirm transaction by signature
USAGE:
solana confirm <SIGNATURE>
FLAGS:
-h, --help Prints help information
-V, --version Prints version information
ARGS:
<SIGNATURE> The transaction signature to confirm
```
```text
solana-deploy
Deploy a program
USAGE:
solana deploy <PATH>
FLAGS:
-h, --help Prints help information
-V, --version Prints version information
ARGS:
<PATH> /path/to/program.o
```
```text
solana-fees
Display current cluster fees
USAGE:
solana fees
FLAGS:
-h, --help Prints help information
-V, --version Prints version information
```
```text
solana-get-transaction-count
Get current transaction count
USAGE:
solana get-transaction-count
FLAGS:
-h, --help Prints help information
-V, --version Prints version information
```
```text
solana-pay
Send a payment
USAGE:
solana pay [FLAGS] [OPTIONS] <PUBKEY> <NUM>
FLAGS:
--cancelable
-h, --help Prints help information
-V, --version Prints version information
OPTIONS:
--after <DATETIME> A timestamp after which transaction will execute
--require-timestamp-from <PUBKEY> Require timestamp from this third party
--require-signature-from <PUBKEY>... Any third party signatures required to unlock the lamports
ARGS:
<PUBKEY> The pubkey of recipient
<NUM> The number of lamports to send
```
```text
solana-send-signature
Send a signature to authorize a transfer
USAGE:
solana send-signature <PUBKEY> <PROCESS_ID>
FLAGS:
-h, --help Prints help information
-V, --version Prints version information
ARGS:
<PUBKEY> The pubkey of recipient
<PROCESS_ID> The process id of the transfer to authorize
```
```text
solana-send-timestamp
Send a timestamp to unlock a transfer
USAGE:
solana send-timestamp [OPTIONS] <PUBKEY> <PROCESS_ID>
FLAGS:
-h, --help Prints help information
-V, --version Prints version information
OPTIONS:
--date <DATETIME> Optional arbitrary timestamp to apply
ARGS:
<PUBKEY> The pubkey of recipient
<PROCESS_ID> The process id of the transfer to unlock
```

View File

@@ -0,0 +1,38 @@
# Instruction
For the purposes of building a [Transaction](../transaction.md), a more verbose instruction format is used:
* **Instruction:**
* **program\_id:** The pubkey of the on-chain program that executes the
instruction
* **accounts:** An ordered list of accounts that should be passed to
the program processing the instruction, including metadata detailing
if an account is a signer of the transaction and if it is a credit
only account.
* **data:** A byte array that is passed to the program executing the
instruction
A more compact form is actually included in a `Transaction`:
* **CompiledInstruction:**
* **program\_id\_index:** The index of the `program_id` in the
`account_keys` list
* **accounts:** An ordered list of indices into `account_keys`
specifying the accounds that should be passed to the program
processing the instruction.
* **data:** A byte array that is passed to the program executing the
instruction

View File

@@ -0,0 +1,788 @@
# JSON RPC API
Solana nodes accept HTTP requests using the [JSON-RPC 2.0](https://www.jsonrpc.org/specification) specification.
To interact with a Solana node inside a JavaScript application, use the [solana-web3.js](https://github.com/solana-labs/solana-web3.js) library, which gives a convenient interface for the RPC methods.
## RPC HTTP Endpoint
**Default port:** 8899 eg. [http://localhost:8899](http://localhost:8899), [http://192.168.1.88:8899](http://192.168.1.88:8899)
## RPC PubSub WebSocket Endpoint
**Default port:** 8900 eg. ws://localhost:8900, [http://192.168.1.88:8900](http://192.168.1.88:8900)
## Methods
* [confirmTransaction](jsonrpc-api.md#confirmtransaction)
* [getAccountInfo](jsonrpc-api.md#getaccountinfo)
* [getBalance](jsonrpc-api.md#getbalance)
* [getClusterNodes](jsonrpc-api.md#getclusternodes)
* [getEpochInfo](jsonrpc-api.md#getepochinfo)
* [getGenesisBlockhash](jsonrpc-api.md#getgenesisblockhash)
* [getLeaderSchedule](jsonrpc-api.md#getleaderschedule)
* [getProgramAccounts](jsonrpc-api.md#getprogramaccounts)
* [getRecentBlockhash](jsonrpc-api.md#getrecentblockhash)
* [getSignatureStatus](jsonrpc-api.md#getsignaturestatus)
* [getSlot](jsonrpc-api.md#getslot)
* [getSlotLeader](jsonrpc-api.md#getslotleader)
* [getSlotsPerSegment](jsonrpc-api.md#getslotspersegment)
* [getStorageTurn](jsonrpc-api.md#getstorageturn)
* [getStorageTurnRate](jsonrpc-api.md#getstorageturnrate)
* [getNumBlocksSinceSignatureConfirmation](jsonrpc-api.md#getnumblockssincesignatureconfirmation)
* [getTransactionCount](jsonrpc-api.md#gettransactioncount)
* [getTotalSupply](jsonrpc-api.md#gettotalsupply)
* [getVersion](jsonrpc-api.md#getversion)
* [getVoteAccounts](jsonrpc-api.md#getvoteaccounts)
* [requestAirdrop](jsonrpc-api.md#requestairdrop)
* [sendTransaction](jsonrpc-api.md#sendtransaction)
* [startSubscriptionChannel](jsonrpc-api.md#startsubscriptionchannel)
* [Subscription Websocket](jsonrpc-api.md#subscription-websocket)
* [accountSubscribe](jsonrpc-api.md#accountsubscribe)
* [accountUnsubscribe](jsonrpc-api.md#accountunsubscribe)
* [programSubscribe](jsonrpc-api.md#programsubscribe)
* [programUnsubscribe](jsonrpc-api.md#programunsubscribe)
* [signatureSubscribe](jsonrpc-api.md#signaturesubscribe)
* [signatureUnsubscribe](jsonrpc-api.md#signatureunsubscribe)
## Request Formatting
To make a JSON-RPC request, send an HTTP POST request with a `Content-Type: application/json` header. The JSON request data should contain 4 fields:
* `jsonrpc`, set to `"2.0"`
* `id`, a unique client-generated identifying integer
* `method`, a string containing the method to be invoked
* `params`, a JSON array of ordered parameter values
Example using curl:
```bash
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getBalance", "params":["83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri"]}' 192.168.1.88:8899
```
The response output will be a JSON object with the following fields:
* `jsonrpc`, matching the request specification
* `id`, matching the request identifier
* `result`, requested data or success confirmation
Requests can be sent in batches by sending an array of JSON-RPC request objects as the data for a single POST.
## Definitions
* Hash: A SHA-256 hash of a chunk of data.
* Pubkey: The public key of a Ed25519 key-pair.
* Signature: An Ed25519 signature of a chunk of data.
* Transaction: A Solana instruction signed by a client key-pair.
## JSON RPC API Reference
### confirmTransaction
Returns a transaction receipt
#### Parameters:
* `string` - Signature of Transaction to confirm, as base-58 encoded string
#### Results:
* `boolean` - Transaction status, true if Transaction is confirmed
#### Example:
```bash
// Request
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"confirmTransaction", "params":["5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW"]}' http://localhost:8899
// Result
{"jsonrpc":"2.0","result":true,"id":1}
```
### getAccountInfo
Returns all information associated with the account of provided Pubkey
#### Parameters:
* `string` - Pubkey of account to query, as base-58 encoded string
#### Results:
The result field will be a JSON object with the following sub fields:
* `lamports`, number of lamports assigned to this account, as a signed 64-bit integer
* `owner`, array of 32 bytes representing the program this account has been assigned to
* `data`, array of bytes representing any data associated with the account
* `executable`, boolean indicating if the account contains a program \(and is strictly read-only\)
#### Example:
```bash
// Request
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getAccountInfo", "params":["2gVkYWexTHR5Hb2aLeQN3tnngvWzisFKXDUPrgMHpdST"]}' http://localhost:8899
// Result
{"jsonrpc":"2.0","result":{"executable":false,"owner":[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"lamports":1,"data":[3,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,50,48,53,48,45,48,49,45,48,49,84,48,48,58,48,48,58,48,48,90,252,10,7,28,246,140,88,177,98,82,10,227,89,81,18,30,194,101,199,16,11,73,133,20,246,62,114,39,20,113,189,32,50,0,0,0,0,0,0,0,247,15,36,102,167,83,225,42,133,127,82,34,36,224,207,130,109,230,224,188,163,33,213,13,5,117,211,251,65,159,197,51,0,0,0,0,0,0]},"id":1}
```
### getBalance
Returns the balance of the account of provided Pubkey
#### Parameters:
* `string` - Pubkey of account to query, as base-58 encoded string
#### Results:
* `integer` - quantity, as a signed 64-bit integer
#### Example:
```bash
// Request
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getBalance", "params":["83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri"]}' http://localhost:8899
// Result
{"jsonrpc":"2.0","result":0,"id":1}
```
### getClusterNodes
Returns information about all the nodes participating in the cluster
#### Parameters:
None
#### Results:
The result field will be an array of JSON objects, each with the following sub fields:
* `pubkey` - Node public key, as base-58 encoded string
* `gossip` - Gossip network address for the node
* `tpu` - TPU network address for the node
* `rpc` - JSON RPC network address for the node, or `null` if the JSON RPC service is not enabled
#### Example:
```bash
// Request
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getClusterNodes"}' http://localhost:8899
// Result
{"jsonrpc":"2.0","result":[{"gossip":"10.239.6.48:8001","pubkey":"9QzsJf7LPLj8GkXbYT3LFDKqsj2hHG7TA3xinJHu8epQ","rpc":"10.239.6.48:8899","tpu":"10.239.6.48:8856"}],"id":1}
```
### getEpochInfo
Returns information about the current epoch
#### Parameters:
None
#### Results:
The result field will be an object with the following fields:
* `epoch`, the current epoch
* `slotIndex`, the current slot relative to the start of the current epoch
* `slotsInEpoch`, the number of slots in this epoch
#### Example:
```bash
// Request
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getEpochInfo"}' http://localhost:8899
// Result
{"jsonrpc":"2.0","result":{"epoch":3,"slotIndex":126,"slotsInEpoch":256},"id":1}
```
### getGenesisBlockhash
Returns the genesis block hash
#### Parameters:
None
#### Results:
* `string` - a Hash as base-58 encoded string
#### Example:
```bash
// Request
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getGenesisBlockhash"}' http://localhost:8899
// Result
{"jsonrpc":"2.0","result":"GH7ome3EiwEr7tu9JuTh2dpYWBJK3z69Xm1ZE3MEE6JC","id":1}
```
### getLeaderSchedule
Returns the leader schedule for the current epoch
#### Parameters:
None
#### Results:
The result field will be an array of leader public keys \(as base-58 encoded strings\) for each slot in the current epoch
#### Example:
```bash
// Request
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getLeaderSchedule"}' http://localhost:8899
// Result
{"jsonrpc":"2.0","result":[...],"id":1}
```
### getProgramAccounts
Returns all accounts owned by the provided program Pubkey
#### Parameters:
* `string` - Pubkey of program, as base-58 encoded string
#### Results:
The result field will be an array of arrays. Each sub array will contain:
* `string` - the account Pubkey as base-58 encoded string and a JSON object, with the following sub fields:
* `lamports`, number of lamports assigned to this account, as a signed 64-bit integer
* `owner`, array of 32 bytes representing the program this account has been assigned to
* `data`, array of bytes representing any data associated with the account
* `executable`, boolean indicating if the account contains a program \(and is strictly read-only\)
#### Example:
```bash
// Request
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getProgramAccounts", "params":["8nQwAgzN2yyUzrukXsCa3JELBYqDQrqJ3UyHiWazWxHR"]}' http://localhost:8899
// Result
{"jsonrpc":"2.0","result":[["BqGKYtAKu69ZdWEBtZHh4xgJY1BYa2YBiBReQE3pe383", {"executable":false,"owner":[50,28,250,90,221,24,94,136,147,165,253,136,1,62,196,215,225,34,222,212,99,84,202,223,245,13,149,99,149,231,91,96],"lamports":1,"data":[]], ["4Nd1mBQtrMJVYVfKf2PJy9NZUZdTAsp7D4xWLs4gDB4T", {"executable":false,"owner":[50,28,250,90,221,24,94,136,147,165,253,136,1,62,196,215,225,34,222,212,99,84,202,223,245,13,149,99,149,231,91,96],"lamports":10,"data":[]]]},"id":1}
```
### getRecentBlockhash
Returns a recent block hash from the ledger, and a fee schedule that can be used to compute the cost of submitting a transaction using it.
#### Parameters:
None
#### Results:
An array consisting of
* `string` - a Hash as base-58 encoded string
* `FeeCalculator object` - the fee schedule for this block hash
#### Example:
```bash
// Request
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getRecentBlockhash"}' http://localhost:8899
// Result
{"jsonrpc":"2.0","result":["GH7ome3EiwEr7tu9JuTh2dpYWBJK3z69Xm1ZE3MEE6JC",{"lamportsPerSignature": 0}],"id":1}
```
### getSignatureStatus
Returns the status of a given signature. This method is similar to [confirmTransaction](jsonrpc-api.md#confirmtransaction) but provides more resolution for error events.
#### Parameters:
* `string` - Signature of Transaction to confirm, as base-58 encoded string
#### Results:
* `null` - Unknown transaction
* `object` - Transaction status:
* `"Ok": null` - Transaction was successful
* `"Err": <ERR>` - Transaction failed with TransactionError [TransactionError definitions](https://github.com/solana-labs/solana/blob/master/sdk/src/transaction.rs#L14)
#### Example:
```bash
// Request
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getSignatureStatus", "params":["5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW"]}' http://localhost:8899
// Result
{"jsonrpc":"2.0","result":"SignatureNotFound","id":1}
```
### getSlot
Returns the current slot the node is processing
#### Parameters:
None
#### Results:
* `u64` - Current slot
#### Example:
```bash
// Request
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getSlot"}' http://localhost:8899
// Result
{"jsonrpc":"2.0","result":"1234","id":1}
```
### getSlotLeader
Returns the current slot leader
#### Parameters:
None
#### Results:
* `string` - Node Id as base-58 encoded string
#### Example:
```bash
// Request
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getSlotLeader"}' http://localhost:8899
// Result
{"jsonrpc":"2.0","result":"ENvAW7JScgYq6o4zKZwewtkzzJgDzuJAFxYasvmEQdpS","id":1}
```
### getSlotsPerSegment
Returns the current storage segment size in terms of slots
#### Parameters:
None
#### Results:
* `u64` - Number of slots in a storage segment
#### Example:
```bash
// Request
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getSlotsPerSegment"}' http://localhost:8899
// Result
{"jsonrpc":"2.0","result":"1024","id":1}
```
### getStorageTurn
Returns the current storage turn's blockhash and slot
#### Parameters:
None
#### Results:
An array consisting of
* `string` - a Hash as base-58 encoded string indicating the blockhash of the turn slot
* `u64` - the current storage turn slot
#### Example:
```bash
// Request
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getStorageTurn"}' http://localhost:8899
// Result
{"jsonrpc":"2.0","result":["GH7ome3EiwEr7tu9JuTh2dpYWBJK3z69Xm1ZE3MEE6JC", "2048"],"id":1}
```
### getStorageTurnRate
Returns the current storage turn rate in terms of slots per turn
#### Parameters:
None
#### Results:
* `u64` - Number of slots in storage turn
#### Example:
```bash
// Request
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getStorageTurnRate"}' http://localhost:8899
// Result
{"jsonrpc":"2.0","result":"1024","id":1}
```
### getNumBlocksSinceSignatureConfirmation
Returns the current number of blocks since signature has been confirmed.
#### Parameters:
* `string` - Signature of Transaction to confirm, as base-58 encoded string
#### Results:
* `integer` - count, as unsigned 64-bit integer
#### Example:
```bash
// Request
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getNumBlocksSinceSignatureConfirmation", "params":["5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW"]}' http://localhost:8899
// Result
{"jsonrpc":"2.0","result":8,"id":1}
```
### getTransactionCount
Returns the current Transaction count from the ledger
#### Parameters:
None
#### Results:
* `integer` - count, as unsigned 64-bit integer
#### Example:
```bash
// Request
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getTransactionCount"}' http://localhost:8899
// Result
{"jsonrpc":"2.0","result":268,"id":1}
```
### getTotalSupply
Returns the current total supply in Lamports
#### Parameters:
None
#### Results:
* `integer` - Total supply, as unsigned 64-bit integer
#### Example:
```bash
// Request
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getTotalSupply"}' http://localhost:8899
// Result
{"jsonrpc":"2.0","result":10126,"id":1}
```
### getVersion
Returns the current solana versions running on the node
#### Parameters:
None
#### Results:
The result field will be a JSON object with the following sub fields:
* `solana-core`, software version of solana-core
#### Example:
```bash
// Request
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getVersion"}' http://localhost:8899
// Result
{"jsonrpc":"2.0","result":{"solana-core": "0.17.2"},"id":1}
```
### getVoteAccounts
Returns the account info and associated stake for all the voting accounts in the current bank.
#### Parameters:
None
#### Results:
The result field will be a JSON object of `current` and `delinquent` accounts, each containing an array of JSON objects with the following sub fields:
* `votePubkey` - Vote account public key, as base-58 encoded string
* `nodePubkey` - Node public key, as base-58 encoded string
* `activatedStake` - the stake, in lamports, delegated to this vote account and active in this epoch
* `epochVoteAccount` - bool, whether the vote account is staked for this epoch
* `commission`, an 8-bit integer used as a fraction \(commission/MAX\_U8\) for rewards payout
* `lastVote` - Most recent slot voted on by this vote account
#### Example:
```bash
// Request
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getVoteAccounts"}' http://localhost:8899
// Result
{"jsonrpc":"2.0","result":{"current":[{"commission":0,"epochVoteAccount":true,"nodePubkey":"B97CCUW3AEZFGy6uUg6zUdnNYvnVq5VG8PUtb2HayTDD","lastVote":147,"activatedStake":42,"votePubkey":"3ZT31jkAGhUaw8jsy4bTknwBMP8i4Eueh52By4zXcsVw"}],"delinquent":[{"commission":127,"epochVoteAccount":false,"nodePubkey":"6ZPxeQaDo4bkZLRsdNrCzchNQr5LN9QMc9sipXv9Kw8f","lastVote":0,"activatedStake":0,"votePubkey":"CmgCk4aMS7KW1SHX3s9K5tBJ6Yng2LBaC8MFov4wx9sm"}]},"id":1}
```
### requestAirdrop
Requests an airdrop of lamports to a Pubkey
#### Parameters:
* `string` - Pubkey of account to receive lamports, as base-58 encoded string
* `integer` - lamports, as a signed 64-bit integer
#### Results:
* `string` - Transaction Signature of airdrop, as base-58 encoded string
#### Example:
```bash
// Request
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"requestAirdrop", "params":["83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri", 50]}' http://localhost:8899
// Result
{"jsonrpc":"2.0","result":"5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW","id":1}
```
### sendTransaction
Creates new transaction
#### Parameters:
* `array` - array of octets containing a fully-signed Transaction
#### Results:
* `string` - Transaction Signature, as base-58 encoded string
#### Example:
```bash
// Request
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"sendTransaction", "params":[[61, 98, 55, 49, 15, 187, 41, 215, 176, 49, 234, 229, 228, 77, 129, 221, 239, 88, 145, 227, 81, 158, 223, 123, 14, 229, 235, 247, 191, 115, 199, 71, 121, 17, 32, 67, 63, 209, 239, 160, 161, 2, 94, 105, 48, 159, 235, 235, 93, 98, 172, 97, 63, 197, 160, 164, 192, 20, 92, 111, 57, 145, 251, 6, 40, 240, 124, 194, 149, 155, 16, 138, 31, 113, 119, 101, 212, 128, 103, 78, 191, 80, 182, 234, 216, 21, 121, 243, 35, 100, 122, 68, 47, 57, 13, 39, 0, 0, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 40, 240, 124, 194, 149, 155, 16, 138, 31, 113, 119, 101, 212, 128, 103, 78, 191, 80, 182, 234, 216, 21, 121, 243, 35, 100, 122, 68, 47, 57, 11, 12, 106, 49, 74, 226, 201, 16, 161, 192, 28, 84, 124, 97, 190, 201, 171, 186, 6, 18, 70, 142, 89, 185, 176, 154, 115, 61, 26, 163, 77, 1, 88, 98, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]}' http://localhost:8899
// Result
{"jsonrpc":"2.0","result":"2EBVM6cB8vAAD93Ktr6Vd8p67XPbQzCJX47MpReuiCXJAtcjaxpvWpcg9Ege1Nr5Tk3a2GFrByT7WPBjdsTycY9b","id":1}
```
### Subscription Websocket
After connect to the RPC PubSub websocket at `ws://<ADDRESS>/`:
* Submit subscription requests to the websocket using the methods below
* Multiple subscriptions may be active at once
* All subscriptions take an optional `confirmations` parameter, which defines
how many confirmed blocks the node should wait before sending a notification.
The greater the number, the more likely the notification is to represent
consensus across the cluster, and the less likely it is to be affected by
forking or rollbacks. If unspecified, the default value is 0; the node will
send a notification as soon as it witnesses the event. The maximum
`confirmations` wait length is the cluster's `MAX_LOCKOUT_HISTORY`, which
represents the economic finality of the chain.
### accountSubscribe
Subscribe to an account to receive notifications when the lamports or data for a given account public key changes
#### Parameters:
* `string` - account Pubkey, as base-58 encoded string
* `integer` - optional, number of confirmed blocks to wait before notification.
Default: 0, Max: `MAX_LOCKOUT_HISTORY` \(greater integers rounded down\)
#### Results:
* `integer` - Subscription id \(needed to unsubscribe\)
#### Example:
```bash
// Request
{"jsonrpc":"2.0", "id":1, "method":"accountSubscribe", "params":["CM78CPUeXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNH12"]}
{"jsonrpc":"2.0", "id":1, "method":"accountSubscribe", "params":["CM78CPUeXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNH12", 15]}
// Result
{"jsonrpc": "2.0","result": 0,"id": 1}
```
#### Notification Format:
```bash
{"jsonrpc": "2.0","method": "accountNotification", "params": {"result": {"executable":false,"owner":[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"lamports":1,"data":[3,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,50,48,53,48,45,48,49,45,48,49,84,48,48,58,48,48,58,48,48,90,252,10,7,28,246,140,88,177,98,82,10,227,89,81,18,30,194,101,199,16,11,73,133,20,246,62,114,39,20,113,189,32,50,0,0,0,0,0,0,0,247,15,36,102,167,83,225,42,133,127,82,34,36,224,207,130,109,230,224,188,163,33,213,13,5,117,211,251,65,159,197,51,0,0,0,0,0,0]},"subscription":0}}
```
### accountUnsubscribe
Unsubscribe from account change notifications
#### Parameters:
* `integer` - id of account Subscription to cancel
#### Results:
* `bool` - unsubscribe success message
#### Example:
```bash
// Request
{"jsonrpc":"2.0", "id":1, "method":"accountUnsubscribe", "params":[0]}
// Result
{"jsonrpc": "2.0","result": true,"id": 1}
```
### programSubscribe
Subscribe to a program to receive notifications when the lamports or data for a given account owned by the program changes
#### Parameters:
* `string` - program\_id Pubkey, as base-58 encoded string
* `integer` - optional, number of confirmed blocks to wait before notification.
Default: 0, Max: `MAX_LOCKOUT_HISTORY` \(greater integers rounded down\)
#### Results:
* `integer` - Subscription id \(needed to unsubscribe\)
#### Example:
```bash
// Request
{"jsonrpc":"2.0", "id":1, "method":"programSubscribe", "params":["9gZbPtbtHrs6hEWgd6MbVY9VPFtS5Z8xKtnYwA2NynHV"]}
{"jsonrpc":"2.0", "id":1, "method":"programSubscribe", "params":["9gZbPtbtHrs6hEWgd6MbVY9VPFtS5Z8xKtnYwA2NynHV", 15]}
// Result
{"jsonrpc": "2.0","result": 0,"id": 1}
```
#### Notification Format:
* `string` - account Pubkey, as base-58 encoded string
* `object` - account info JSON object \(see [getAccountInfo](jsonrpc-api.md#getaccountinfo) for field details\)
```bash
{"jsonrpc":"2.0","method":"programNotification","params":{{"result":["8Rshv2oMkPu5E4opXTRyuyBeZBqQ4S477VG26wUTFxUM",{"executable":false,"lamports":1,"owner":[129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"data":[1,1,1,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,50,48,49,56,45,49,50,45,50,52,84,50,51,58,53,57,58,48,48,90,235,233,39,152,15,44,117,176,41,89,100,86,45,61,2,44,251,46,212,37,35,118,163,189,247,84,27,235,178,62,55,89,0,0,0,0,50,0,0,0,0,0,0,0,235,233,39,152,15,44,117,176,41,89,100,86,45,61,2,44,251,46,212,37,35,118,163,189,247,84,27,235,178,62,45,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}],"subscription":0}}
```
### programUnsubscribe
Unsubscribe from program-owned account change notifications
#### Parameters:
* `integer` - id of account Subscription to cancel
#### Results:
* `bool` - unsubscribe success message
#### Example:
```bash
// Request
{"jsonrpc":"2.0", "id":1, "method":"programUnsubscribe", "params":[0]}
// Result
{"jsonrpc": "2.0","result": true,"id": 1}
```
### signatureSubscribe
Subscribe to a transaction signature to receive notification when the transaction is confirmed On `signatureNotification`, the subscription is automatically cancelled
#### Parameters:
* `string` - Transaction Signature, as base-58 encoded string
* `integer` - optional, number of confirmed blocks to wait before notification.
Default: 0, Max: `MAX_LOCKOUT_HISTORY` \(greater integers rounded down\)
#### Results:
* `integer` - subscription id \(needed to unsubscribe\)
#### Example:
```bash
// Request
{"jsonrpc":"2.0", "id":1, "method":"signatureSubscribe", "params":["2EBVM6cB8vAAD93Ktr6Vd8p67XPbQzCJX47MpReuiCXJAtcjaxpvWpcg9Ege1Nr5Tk3a2GFrByT7WPBjdsTycY9b"]}
{"jsonrpc":"2.0", "id":1, "method":"signatureSubscribe", "params":["2EBVM6cB8vAAD93Ktr6Vd8p67XPbQzCJX47MpReuiCXJAtcjaxpvWpcg9Ege1Nr5Tk3a2GFrByT7WPBjdsTycY9b", 15]}
// Result
{"jsonrpc": "2.0","result": 0,"id": 1}
```
#### Notification Format:
```bash
{"jsonrpc": "2.0","method": "signatureNotification", "params": {"result": "Confirmed","subscription":0}}
```
### signatureUnsubscribe
Unsubscribe from signature confirmation notification
#### Parameters:
* `integer` - subscription id to cancel
#### Results:
* `bool` - unsubscribe success message
#### Example:
```bash
// Request
{"jsonrpc":"2.0", "id":1, "method":"signatureUnsubscribe", "params":[0]}
// Result
{"jsonrpc": "2.0","result": true,"id": 1}
```

View File

@@ -0,0 +1,63 @@
# Transaction
## Components of a `Transaction`
* **Transaction:**
* **message:** Defines the transaction
* **header:** Details the account types of and signatures required by
the transaction
* **num\_required\_signatures:** The total number of signatures
required to make the transaction valid.
* **num\_credit\_only\_signed\_accounts:** The last
`num_credit_only_signed_accounts` signatures refer to signing
credit only accounts. Credit only accounts can be used concurrently
by multiple parallel transactions, but their balance may only be
increased, and their account data is read-only.
* **num\_credit\_only\_unsigned\_accounts:** The last
`num_credit_only_unsigned_accounts` pubkeys in `account_keys` refer
to non-signing credit only accounts
* **account\_keys:** List of pubkeys used by the transaction, including
by the instructions and for signatures. The first
`num_required_signatures` pubkeys must sign the transaction.
* **recent\_blockhash:** The ID of a recent ledger entry. Validators will
reject transactions with a `recent_blockhash` that is too old.
* **instructions:** A list of [instructions](https://github.com/solana-labs/solana/tree/6b18db969dd1616eff07de35e7b823c75339fea8/book/src/instruction.md) that are
run sequentially and committed in one atomic transaction if all
succeed.
* **signatures:** A list of signatures applied to the transaction. The
list is always of length `num_required_signatures`, and the signature
at index `i` corresponds to the pubkey at index `i` in `account_keys`.
The list is initialized with empty signatures \(i.e. zeros\), and
populated as signatures are added.
## Transaction Signing
A `Transaction` is signed by using an ed25519 keypair to sign the serialization of the `message`. The resulting signature is placed at the index of `signatures` matching the index of the keypair's pubkey in `account_keys`.
## Transaction Serialization
`Transaction`s \(and their `message`s\) are serialized and deserialized using the [bincode](https://crates.io/crates/bincode) crate with a non-standard vector serialization that uses only one byte for the length if it can be encoded in 7 bits, 2 bytes if it fits in 14 bits, or 3 bytes if it requires 15 or 16 bits. The vector serialization is defined by Solana's [short-vec](https://github.com/solana-labs/solana/blob/master/sdk/src/short_vec.rs).

View File

@@ -4,7 +4,7 @@ A validator votes on a PoH hash for two purposes. First, the vote indicates it
believes the ledger is valid up until that point in time. Second, since many believes the ledger is valid up until that point in time. Second, since many
valid forks may exist at a given height, the vote also indicates exclusive valid forks may exist at a given height, the vote also indicates exclusive
support for the fork. This document describes only the former. The latter is support for the fork. This document describes only the former. The latter is
described in [Tower BFT](../implemented-proposals/tower-bft.md). described in [Tower BFT](tower-bft.md).
## Current Design ## Current Design
@@ -17,7 +17,7 @@ height of the block it is voting on. The account stores the 32 highest heights.
* Only the validator knows how to find its own votes directly. * Only the validator knows how to find its own votes directly.
Other components, such as the one that calculates confirmation time, needs to Other components, such as the one that calculates confirmation time, needs to
be baked into the validator code. The validator code queries the bank for all be baked into the fullnode code. The fullnode code queries the bank for all
accounts owned by the vote program. accounts owned by the vote program.
* Voting ballots do not contain a PoH hash. The validator is only voting that * Voting ballots do not contain a PoH hash. The validator is only voting that
@@ -50,7 +50,7 @@ log the time since the NewBlock transaction was submitted.
### Finality and Payouts ### Finality and Payouts
[Tower BFT](../implemented-proposals/tower-bft.md) is the proposed fork selection algorithm. It proposes [Tower BFT](tower-bft.md) is the proposed fork selection algorithm. It proposes
that payment to miners be postponed until the *stack* of validator votes reaches that payment to miners be postponed until the *stack* of validator votes reaches
a certain depth, at which point rollback is not economically feasible. The vote a certain depth, at which point rollback is not economically feasible. The vote
program may therefore implement Tower BFT. Vote instructions would need to program may therefore implement Tower BFT. Vote instructions would need to

37
book/src/blockstreamer.md Normal file
View File

@@ -0,0 +1,37 @@
# Blockstreamer
Solana supports a node type called an *blockstreamer*. This fullnode variation
is intended for applications that need to observe the data plane without
participating in transaction validation or ledger replication.
A blockstreamer runs without a vote signer, and can optionally stream ledger
entries out to a Unix domain socket as they are processed. The JSON-RPC service
still functions as on any other node.
To run a blockstreamer, include the argument `no-signer` and (optional)
`blockstream` socket location:
```bash
$ ./multinode-demo/validator-x.sh --no-signer --blockstream <SOCKET>
```
The stream will output a series of JSON objects:
- An Entry event JSON object is sent when each ledger entry is processed, with
the following fields:
* `dt`, the system datetime, as RFC3339-formatted string
* `t`, the event type, always "entry"
* `s`, the slot height, as unsigned 64-bit integer
* `h`, the tick height, as unsigned 64-bit integer
* `entry`, the entry, as JSON object
- A Block event JSON object is sent when a block is complete, with the
following fields:
* `dt`, the system datetime, as RFC3339-formatted string
* `t`, the event type, always "block"
* `s`, the slot height, as unsigned 64-bit integer
* `h`, the tick height, as unsigned 64-bit integer
* `l`, the slot leader id, as base-58 encoded string
* `id`, the block id, as base-58 encoded string

102
book/src/blocktree.md Normal file
View File

@@ -0,0 +1,102 @@
# Blocktree
After a block reaches finality, all blocks from that one on down
to the genesis block form a linear chain with the familiar name
blockchain. Until that point, however, the validator must maintain all
potentially valid chains, called *forks*. The process by which forks
naturally form as a result of leader rotation is described in
[fork generation](fork-generation.md). The *blocktree* data structure
described here is how a validator copes with those forks until blocks
are finalized.
The blocktree allows a validator to record every shred it observes
on the network, in any order, as long as the shred is signed by the expected
leader for a given slot.
Shreds are moved to a fork-able key space the tuple of `leader slot` + `shred
index` (within the slot). This permits the skip-list structure of the Solana
protocol to be stored in its entirety, without a-priori choosing which fork to
follow, which Entries to persist or when to persist them.
Repair requests for recent shreds are served out of RAM or recent files and out
of deeper storage for less recent shreds, as implemented by the store backing
Blocktree.
### Functionalities of Blocktree
1. Persistence: the Blocktree lives in the front of the nodes verification
pipeline, right behind network receive and signature verification. If the
shred received is consistent with the leader schedule (i.e. was signed by the
leader for the indicated slot), it is immediately stored.
2. Repair: repair is the same as window repair above, but able to serve any
shred that's been received. Blocktree stores shreds with signatures,
preserving the chain of origination.
3. Forks: Blocktree supports random access of shreds, so can support a
validator's need to rollback and replay from a Bank checkpoint.
4. Restart: with proper pruning/culling, the Blocktree can be replayed by
ordered enumeration of entries from slot 0. The logic of the replay stage
(i.e. dealing with forks) will have to be used for the most recent entries in
the Blocktree.
### Blocktree Design
1. Entries in the Blocktree are stored as key-value pairs, where the key is the concatenated
slot index and shred index for an entry, and the value is the entry data. Note shred indexes are zero-based for each slot (i.e. they're slot-relative).
2. The Blocktree maintains metadata for each slot, in the `SlotMeta` struct containing:
* `slot_index` - The index of this slot
* `num_blocks` - The number of blocks in the slot (used for chaining to a previous slot)
* `consumed` - The highest shred index `n`, such that for all `m < n`, there exists a shred in this slot with shred index equal to `n` (i.e. the highest consecutive shred index).
* `received` - The highest received shred index for the slot
* `next_slots` - A list of future slots this slot could chain to. Used when rebuilding
the ledger to find possible fork points.
* `last_index` - The index of the shred that is flagged as the last shred for this slot. This flag on a shred will be set by the leader for a slot when they are transmitting the last shred for a slot.
* `is_rooted` - True iff every block from 0...slot forms a full sequence without any holes. We can derive is_rooted for each slot with the following rules. Let slot(n) be the slot with index `n`, and slot(n).is_full() is true if the slot with index `n` has all the ticks expected for that slot. Let is_rooted(n) be the statement that "the slot(n).is_rooted is true". Then:
is_rooted(0)
is_rooted(n+1) iff (is_rooted(n) and slot(n).is_full()
3. Chaining - When a shred for a new slot `x` arrives, we check the number of blocks (`num_blocks`) for that new slot (this information is encoded in the shred). We then know that this new slot chains to slot `x - num_blocks`.
4. Subscriptions - The Blocktree records a set of slots that have been "subscribed" to. This means entries that chain to these slots will be sent on the Blocktree channel for consumption by the ReplayStage. See the `Blocktree APIs` for details.
5. Update notifications - The Blocktree notifies listeners when slot(n).is_rooted is flipped from false to true for any `n`.
### Blocktree APIs
The Blocktree offers a subscription based API that ReplayStage uses to ask for entries it's interested in. The entries will be sent on a channel exposed by the Blocktree. These subscription API's are as follows:
1. `fn get_slots_since(slot_indexes: &[u64]) -> Vec<SlotMeta>`: Returns new slots connecting to any element of the list `slot_indexes`.
2. `fn get_slot_entries(slot_index: u64, entry_start_index: usize, max_entries: Option<u64>) -> Vec<Entry>`: Returns the entry vector for the slot starting with `entry_start_index`, capping the result at `max` if `max_entries == Some(max)`, otherwise, no upper limit on the length of the return vector is imposed.
Note: Cumulatively, this means that the replay stage will now have to know when a slot is finished, and subscribe to the next slot it's interested in to get the next set of entries. Previously, the burden of chaining slots fell on the Blocktree.
### Interfacing with Bank
The bank exposes to replay stage:
1. `prev_hash`: which PoH chain it's working on as indicated by the hash of the last
entry it processed
2. `tick_height`: the ticks in the PoH chain currently being verified by this
bank
3. `votes`: a stack of records that contain:
1. `prev_hashes`: what anything after this vote must chain to in PoH
2. `tick_height`: the tick height at which this vote was cast
3. `lockout period`: how long a chain must be observed to be in the ledger to
be able to be chained below this vote
Replay stage uses Blocktree APIs to find the longest chain of entries it can
hang off a previous vote. If that chain of entries does not hang off the
latest vote, the replay stage rolls back the bank to that vote and replays the
chain from there.
### Pruning Blocktree
Once Blocktree entries are old enough, representing all the possible forks
becomes less useful, perhaps even problematic for replay upon restart. Once a
validator's votes have reached max lockout, however, any Blocktree contents
that are not on the PoH chain for that vote for can be pruned, expunged.
Replicator nodes will be responsible for storing really old ledger contents,
and validators need only persist their bank periodically.

Some files were not shown because too many files have changed in this diff Show More