In the error case that i>0 (we have blobs to send)
we break out of the loop and do not push the allocated r
to the v array. We should recycle this blob, otherwise it
will be dropped.
* fix poll_gossip_for_leader() loop to actually wait
for 30 seconds
* reduce reuseaddr use to only when necessary,
try to avoid already bound sockets
* move nat.rs to netutil.rs
* add gossip tracing to thin_client and bench-tps
* Migrate Budget DSL to use the Account state instead of global bank data structures.
* Serialize Instruction into Transaction::userdata.
* Store the pending set in the Account::userdata
* Enforce the token balance rules on contract execution. This becomes the entry point for generic contracts.
* This pr will have a performance impact on the bank. The next set of changes will fix this by locking each account during multi threaded execution of all the contracts.
* With this change a contract transaction needs to store its state under an address. That address could be the destination of the tokens, or any random address. For the latter, an extra step would be needed to claim the tokens which isn't implemented by budget_dsl at the moment.
* test tracking issue 1157
* remove client.sh from snap
* default to ephemeral instead of ~/.config key
* rework CLI for bench-tps
* remote multinode-demo stuff from remote-client.sh
* remove multinode-demo from remote-sanity and localnet-sanity
It needed to be passed the lock before, because it contained a
branch where one side didn't require locking. Now that that
defensive programming was hoisted, we can hoist the write lock
as well, leaving a simpler function for unit testing.
Even if transactions are dropped, accounts will have buffer
of tokens. Should reduce or eliminate AccountNotFound errors seen in the
leader while bench-tps is running.
* Reuse UDP port and open multiple sockets for transaction address
* Fixed failing crdt tests
* Add tests for reusing UDP ports
* Address review comments
* Updated bench-streamer to use multiple receive sockets
* Fix minimum number of recv sockets for bench-streamer
* Address review comments
Fixes#1132
* Moved bind_to function to nat.rs
* use USER instead of whoami
make gcloud_FigureRemoteUsername robust against unsolicited output
(that I get on login ;) )
validate --prefix argument
* Update gcloud.sh
If balance goes to 0, then bank removes the account
from it's account table and returns no account error. Thin client
should also update the account to this state or it will
still have the cached balance from the last successful get_balance().
* rename NodeInfo field of Node from "data" to "info"
(touches a lot of files)
* update client to use gossip to find leader, a la drone
* rework multinode scripts
* move more stuff into rust
* added usage to all
* no more rsync unless you're a validator (TODO: whack that, too)
* fullnode doesn't bail if drone isn't up yet, just keeps trying
* drone doesn't bail if network isn't up yet, just keeps trying
* remove trailing whitespace in ci/audit.sh
* code review fixups
* rename GOSSIP_PORT_RANGE => SOLANA_PORT_RANGE
* remove out-of-date TODO in localnet-sanity.sh
* remove features=test and code that was using it (localhost prohibitions in
crdt) added TODO in crdt.rs, maybe we should boot localhost in production
networks?
* boot tvu_window from NodeInfo: instead, send repair requests from the repair
socket (to gossip on peer) and answer repair requests via the sockaddr
from the repair request
* remove various unused pub functions
* banish SocketAddr parse().unwrap() to a macro that can also accept simpler stuff
* move gossip/NCP off assuming anything about its address
* use a single socket to send and receive gossip
* remove --addr/-a from CLIs
* rearrange networking utility code
* use Arc<UdpSocket> to share the Sync-safe UdpSocket among threads
* rename TestNode to Node
TODO:
* re-enable 127.0.0.1 as a valid address in crdt
* change repair request/response to a similar, single socket
* pick cloned sockets or Arc<UdpSocket> for all these (rpu uses tryclone())
* update contact_info with network truthiness instead of what the node
says?
And update transaction offsets to use the same approach as packet.rs.
Maybe this should be serialized_size(), but thanks to this
GenericArray update, those values are the same.
* Added poll_balance_with_timeout method
- updated bench-tps, fullnode and wallet to use this method instead
of repeatedly calling poll_get_balance()
* Address review comments
- Revert some changes to use wrapper poll_get_balance()
* Reverting bench-tps to use poll_get_balance
- The original code is checking if the balance has been updated,
instead of just retrieving the balance. The logic is different
than poll_balance_with_timeout()
* Reverting wallet to use poll_get_balance
- The break condition in the loop is different than poll_balance_with_timeout().
It's checking if the balance has been updated.
Situation is there can be that there can be bad entries in
the bench-tps CRDT table until they get purged later. Threads however
are created for those bad entries and then will hang on trying
to get the transaction_count from those bad addresses and never end.
* Revert benchmarks back to libtest
Criterion has too many dependencies, it's execution as slower, and
we didn't see the kind of precision we had hoped for to use it to
block CI builds.
* Ignore benchmarks that take more than a few milliseconds per iteration
* Revert "Ignore benchmarks that take more than a few milliseconds per iteration"
This reverts commit b87cdf6ef4.
* Don't run benchmarks in CI
They are already built in the nightly build. Executing them in CI
doesn't add much value until the results are precise enough to act
on.
# This is the 1st commit message:
Fix tesetment readme
# This is the commit message #2:
updte
# This is the commit message #3:
typo
# This is the commit message #4:
cleanup
comments
fixups!
fixups!
fixups for a real Result<> from get_balance()
on 2nd thought, be more rigorous
Merge branch 'rob-solana-accounts_with_state' into accounts_with_state
update
review comments
comments
get rid of option
- Some nodes don't have leader information while leader is broadcasting
blobs to those nodes. Such blobs are not retransmitted. This change
rertansmits the blobs once the leader's identity is know.
* add json, which does the thing with json, move print to Rust's {:?}
* add --head NUM, to limit how much work gets done for print, json, verify
* add verify-internal, which very carefully checks ledger format without
trying first to "recover" it
* exit with errors on mis-usage
We'll avoid introducing three-letter terms to free up the namespace
for three-letter acronyms.
But recognize the term "sigverify", a verb, to verify a digital
signature.
clear flags on fresh blobs, lest they sometimes impersonate coding blobs...
fix bug: advance *received whether the blob_index is in the window or not,
failure to do so results in a stalled repair request pipeline
bank will only register ids when has_more is not set because those are
the only ids it has advertised, so it will not register all ids,
however the entry stream will contain unbroken last_id chain, so we
need to track that to get the correct start hash.
All CLI apps that use clap (in other words, except for bench-streamer)
can use crate_version! to take the version from Cargo.toml.
This change addresses #700.
Don't recover() for copy(), as copy() is already tolerant of things
recover() guards against. Note: recover() is problematic if the ledger is
"live", i.e. is currently being written to.
* add recover_ledger() to deal with expected common ledger corruptions
* add verify_ledger() for future use cases (ledger-tool)
* increase ledger testing
* allow replicate stage to run without a ledger
* ledger-tool to output valid json
This was introduced to mask the occasional failure of racy tests. But this is misguided as it helps hid the true problem, the racy test, and it causes tries builds that fail deterministically to retry only to fail once again.
* fixup!
* fixups!
* send the vote and count it
* actually vote
* test
* Spelling fixes
* Process the voting transaction in the leader's bank
* Send tokens to the leader
* Give leader tokens in more cases
* Test for write_stage::leader_vote
* Request airdrop inside fullnode and not the script
* Change readme to indicate that drone should be up before leader
And start drone before leader in snap scripts
* Rename _kp => _keypair for keypairs and other review fixups
* Remove empty else
* tweak test_leader_vote numbers to be closer to testing 2/3 boundary
* combine creating blob and transaction for leader/validator
- No sigverify if feature sigverify_cpu_disable is used
- Purge validators in the test if lag count increases beyond
SOLANA_DYNAMIC_NODES_PURGE_LAG environment variable
- Other useful log messages in the test
While polling for a non-zero balance, it's not uncommon for one of the
get_balance requests to fail with EWOULDBLOCK. Previously when a get_balance
request failure occurred on the last iteration of the polling loop,
poll_get_balance returned an error even though the N-1 iterations may have
successfully retrieved a balance of 0.
erasure coding blobs were being counted as window slots, skewing transmit_index
erasure coding blobs were being skipped over for broadcast, because they're
only generated when the last data blob in an erasure block is added to the
window.... rewind the index to pick up and broadcast those coding blobs
- Create a known_hosts file if it doesn't exist
Otherwise ssh-keygen exits
- Move some common rsync code to common_start_setup
- Build the project before deploying it
Clippy told us to change function parameters to references, but
wasn't able to then tell us that the clone() before borrowing
was superfluous. This patch removes those by hand.
No expectation of a performance improvement here, since we were
just cloning reference counts. Just removes a bunch of noise.
* log responder error to warn
* log responder error to warn
* fixup!
* fixed assert
* fixed bad ports issue
* comments
* test for dummy address in Crdt::new instaad of NodeInfo::new
* return error if ContactInfo supplied to Crdt::new cannot be used to connect to network
* comments
Keep stdout clean for the actual program. This is a specific concern for the
wallet command, where there exists tests that capture stdout from the wallet to
confirm transactions.
- This script outputs the IP address array that can be used
with start_nodes script to launch multinode demo
- Changes to start_nodes to compress files for rsync
wip
voting
wip
move voting into the replicate stage
update
fixup!
fixup!
fixup!
fixup!
fixup!
fixup!
fixup!
fixup!
fixup!
fixup!
update
fixup!
fixup!
fixup!
tpu processing votes in entries before write stage
fixup!
fixup!
txs
make sure validators have an account
fixup!
fixup!
fixup!
exit fullnode correctly
exit on exit not err
try 50
add delay for voting
300
300
startup logs
par start
100
no rayon
retry longer
log leader drop
fix distance
50 nodes
100
handle deserialize error
update
fix broadcast
new table every time
tweaks
table
update
try shuffle table
skip kill
skip add
purge test
fixed tests
rebase 2
fixed tests
fixed rebase
cleanup
ok for blobs to be longer then window
fix init window
60 nodes
Per @aeyakovenko, contracts shouldn't trust the network for
timestamps. Instead, pass the verified public key to the
contract and let it decide if that's a public key it wants
to trust the timestamp from.
Fixes#405
Error handling is still clumsy. We should switch to something like
`error-chain` or `Result<T, Box<Error>>`, but until then, we can
at least be consistent across modules.
This also fixes a bug in the thin client where a nonexistent account
would have triggered a panic because we were using `balances[k]` instead
of `balances.get(key)`.
Fixes#534
Reaching into the stages' structs for their receivers is, in hindsight,
more awkward than returning multiple values from constructors. By
returning the receiver, the caller can name the receiver whatever it
wants (as you would with any return value), and doesn't need to
reach into the struct for the field (which is super awkward in
combination with move semantics).
The new read_entries() works, but is overly-contrained. Not
using that function yet, but adding it here in the hopes some
Rust guru will tell us how to get that lifetime constraint out
of there.
Fixes#517
1. Use pre-installed host rust toolchain
2. Build reference/performance fullnode in same part to avoid rebuilding libraries
3. Merge scripts into same part
UPnP is now used to request a port on the NAT be forwarded to the local machine.
This obviously only works for NATs that support UPnP, and thus is not a panacea
for all NAT-related connectivity issues.
Notable hacks in this patch include a transmit/receive UDP socket pair to work
around current protocol limitations whereby the full node assumes its peer can
receive on the same UDP port it transmitted from.
* The built code is loaded to the nodes
* ssh_keys can be copied to the nodes for internode comm
* The nodes are started with their respective roles
* The client demo is started on the last node
Otherwise we will just warn about overrun and not insert new blob
Also, break if the index we find is less than consumed otherwise
we can infinite loop
Instead of asserting ref count is 1 before recycling, allow users
to recycle items early. If it turns out that was too early, and
allocate() wants to return it, then boot it and take a memory
allocation performance hit instead.
* Send transactions from the mint's private key
* By default, send full balance to oneself
* By default, request the mint's number of tokens for airdrops
Now that the Bank is single-threaded again, we can spin up new
accounts on the fly without concern of thread contention. Likewise,
we can send all transactions from a single account, which was also
problematic in the multi-threaded bank. Sending from one account will
also make client-demo straightforward to port to solana-drone.
This change will make these benchmarks way slower, because its now
cloning the transaction vector each iteration instead of the ref
counts. We need to rethink these.
This patch likely fixes the sporadic failures in the following tests:
```
test server::tests::validator_exit ... FAILED
test streamer::test::streamer_send_test ... FAILED
test thin_client::tests::test_bad_sig ... FAILED
test drone::tests::test_send_airdrop ... FAILED
test thin_client::tests::test_thin_client ... FAILED
```
This might fix an awful bug where the streamer reuses a Blob
before the current user is done with it. Recycler should probably
assert ref count is one?
* Also don't collect() an iterator before iterating over it.
pnet_transport takes a long time to build. It's been especially
painful from within a docker container for reasons I don't care
to understand. pnet_datalink is the only part of pnet we're using
so booting the rest.
IPADDR is simple, but not exactly what we need for testnet, where NAT'd
folks need to join in, need to advertize themselves as on the interweb.
myip() helps, but there's some TODOs: fullnode-config probably needs to
be told where it lives in the real world (machine interfaces tell us dick),
or incorporate something like the "ifconfig.co" code in myip.sh
* limit the number of Tntries per Blob to at most one
* limit the number of Transactions per Entry such that an Entry will
always fit in a Blob
With a one-to-one map of Entries to Blobs, recovery of a validator
is a simple fast-forward from the end of the initial genesis.log
and tx-*.logs Entries.
TODO: initialize validators' blob index with initial # of Entries.
* add setup to combine init steps, configurable initial mint
* bash -e -> bash and be explicit about errors with || exit $?
* feed transaction logs to validator, too
* use a line iterator on stdin instead of a line iterator on a buffer
* move some unwrap() to expect(), documenting failures
* bind entry type earlier (for kicks)
* fix documentation, other opt parameters
* add support for a named output file, remove hardcoded "leader.log"
* resurrect stdout as the default output
Refactored TVU, into stages
* blob fetch stage for blobs
* window stage for maintaining the blob window
* pulled out NCP out of the TVU so they can be separate units
TVU is now just the fetch -> window -> request and bank processing
* Needed for #341. Create a dummy entry with public key 0..., but with a valid gossip address that we can ask for updates. This will allow validators to discover the full network by just knowing a single node's gossip address without knowing anything else about their identity.
* once we start removing dead validators this entry should get purged since we will never see a message from public key 0, #344
It's not always a problem if line coverage drops. For example,
coverage will drop if you make well-tested code more succinct.
It just means the uncovered code is just a larger percentage of
the codebase.
Because we keep changing those scripts and not updating the readme.
Also, this removes the "-b 9000" starting validators. Is that right?
Or should we be passing that to the validator config?
The first header and its content is the only text displayed on
GitHub's mobile page. Reorder so that the disclaimer is the only
information people see.
Disclaimer: IANAL and assume reordering these doesn't matter. :)
We added them thinking it'd be a good stepping stone towards an
asynchronous thin client, but it's used inconsistently and where
it used, the function is still synchronous, which is just confusing.
History: the function was pulled out of Bank when each field wasn't
wrapped in a RwLock, and that locking 'balances' meant to lock
everything in the bank. Now that the RwLocks are here to stay,
we can make it a method again.
History: Qualifying the method names with 'verified' was done to
distinguish them from methods that first did signature verification.
After we moved all signature verication to SigVerifyStage, we removed
those methods from Bank, leaving only the 'verified' ones.
This patch removes the word 'verified' from all method names, since
it is now implied by any code running after SigVerifyStage.
poll both endpoints in client
logs
logs
logs
names
verify plan not sig
log
set udp buffer to max
drop output
more verbose about window requests
log the leader
load leader identity
readme for single node demo
update
asserts
update
replay all
rsync
dynamic file read in testnode
fix
cleanup
readme
sum
fix scripts
cleanup
cleanup
readme
This makes record_stage consistent with the other stages. The stage
manages the channels. Anything else is in a standalone object. In
the case of the record_stage, that leaves almost nothing!
No longer intercept entries to register_entry_id(). Intead,
register the ID in the Write stage.
EventProcessor is now just being used as a place to store data.
Fixes#216
We were accessing the accountant from multiple stages just to
register the ID the historian adds to Events.
This change should cause a whole lot of Arcs and Mutexes to go away.
The terms Stub and Skel come from OMG IDL and only made sense while
the Stub was acting as an RPC client for the the Accountant object.
Nowadays, the Stub interface looks nothing like the Accountant and
meanwhile we've recognized the multithreaded implementation is more
reminiscent of a pipelined CPU. Thus, we finally bite the bullet and
rename our modules.
AccountantSkel -> Tpu
AccountantStub -> ThinClient
Up next will be moving much of the TPU code into separate modules,
each representing a stage of the pipeline. The interface of each
will follow the precedent set by the Historian object.
If you checked here yesterday, this was a top-level file in git-lfs,
but that made the developer workflow more painful so we boot that
file and are making it available via an http endpoint.
* Replace magic numbers for 64k event size
* Fix gossip, dont ping yourself
* Retransmit only to listening nodes
* Multinode test in stub marked unstable
This is more precice than the previous implementation because it'll
drain the EntryInfo queue and return the most recent last_id instead
of the first one.
Solana™ 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.
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.
Solana: High Performance Blockchain
===
Solana™ is a new architecture for a high performance blockchain. It aims to support
over 700 thousand transactions per second on a gigabit network.
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 178 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)]. 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! Furthermore, and much to our surprise, it can 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 in route towards that theoretical limit of 710,000 transactions per second.
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!
Running the demo
> 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 in route towards that theoretical limit of 710,000 transactions per second.
Testnet Demos
===
The Solana repo contains all the scripts you might need to spin up your own
local testnet. Depending on what you're looking to achieve, you may want to
run a different variation, as the full-fledged, performance-enhanced
multinode testnet is considerably more complex to set up than a Rust-only,
singlenode testnode. If you are looking to develop high-level features, such
as experimenting with smart contracts, save yourself some setup headaches and
stick to the Rust-only singlenode demo. If you're doing performance optimization
of the transaction pipeline, consider the enhanced singlenode demo. If you're
doing consensus work, you'll need at least a Rust-only multinode demo. If you want
to reproduce our TPS metrics, run the enhanced multinode demo.
For all four variations, you'd need the latest Rust toolchain and the Solana
You can observe the effects of your client's transactions on our [dashboard](https://metrics.solana.com:3000/d/testnet/testnet-hud?orgId=2&from=now-30m&to=now&refresh=5s&var-testnet=testnet)
Linux Snap
---
A Linux [Snap](https://snapcraft.io/) is available, which can be used to
easily get Solana running on supported Linux systems without building anything
from source. The `edge` Snap channel is updated daily with the latest
development from the `master` branch. To install:
```bash
$ sudo snap install solana --edge --devmode
```
(`--devmode` flag is required only for `solana.fullnode-cuda`)
Once installed the usual Solana programs will be available as `solona.*` instead
of `solana-*`. For example, `solana.fullnode` instead of `solana-fullnode`.
Update to the latest version at any time with:
```bash
$ snap info solana
$ sudo snap refresh solana --devmode
```
### Daemon support
The snap supports running a leader, validator or leader+drone node as a system
daemon.
Run `sudo snap get solana` to view the current daemon configuration. To view
daemon logs:
1. Run `sudo snap logs -n=all solana` to view the daemon initialization log
2. Runtime logging can be found under `/var/snap/solana/current/leader/`,
`/var/snap/solana/current/validator/`, or `/var/snap/solana/current/drone/` depending
on which `mode=` was selected. Within each log directory the file `current`
contains the latest log, and the files `*.s` (if present) contain older rotated
logs.
Disable the daemon at any time by running:
```bash
$ sudo snap set solana mode=
```
Runtime configuration files for the daemon can be found in
`/var/snap/solana/current/config`.
#### Leader daemon
```bash
$ sudo snap set solana mode=leader
```
If CUDA is available:
```bash
$ sudo snap set solana mode=leader enable-cuda=1
```
`rsync` must be configured and running on the leader.
1. Ensure rsync is installed with `sudo apt-get -y install rsync`
2. Edit `/etc/rsyncd.conf` to include the following
```
[config]
path = /var/snap/solana/current/config
hosts allow = *
read only = true
```
3. Run `sudo systemctl enable rsync; sudo systemctl start rsync`
4. Test by running `rsync -Pzravv rsync://<ip-address-of-leader>/config
solana-config` from another machine. **If the leader is running on a cloud
provider it may be necessary to configure the Firewall rules to permit ingress
to port tcp:873, tcp:9900 and the port range udp:8000-udp:10000**
To run both the Leader and Drone:
```bash
$ sudo snap set solana mode=leader+drone
```
#### Validator daemon
```bash
$ sudo snap set solana mode=validator
```
If CUDA is available:
```bash
$ sudo snap set solana mode=validator enable-cuda=1
```
By default the validator will connect to **testnet.solana.com**, override
the leader IP address by running:
```bash
$ sudo snap set solana mode=validator leader-address=127.0.0.1 #<-- change IP address
```
It's assumed that the leader will be running `rsync` configured as described in
the previous **Leader daemon** section.
Developing
===
@ -102,6 +276,18 @@ $ source $HOME/.cargo/env
$ rustup component add rustfmt-preview
```
If your rustc version is lower than 1.26.1, please update it:
```bash
$ rustup update
```
On Linux systems you may need to install libssl-dev, pkg-config, zlib1g-dev, etc. On Ubuntu:
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.
The goal of this RFC is to define a set of constraints for APIs and runtime such that we can execute our smart contracts safely on massively parallel hardware such as a GPU. Our runtime is built around an OS *syscall* primitive. The difference in blockchain is that now the OS does a cryptographic check of memory region ownership before accessing the memory in the Solana kernel.
## Version
version 0.2
## Toolchain Stack
+---------------------+ +---------------------+
| | | |
| +------------+ | | +------------+ |
| | | | | | | |
| | frontend | | | | verifier | |
| | | | | | | |
| +-----+------+ | | +-----+------+ |
| | | | | |
| | | | | |
| +-----+------+ | | +-----+------+ |
| | | | | | | |
| | llvm | | | | loader | |
| | | +------>+ | | |
| +-----+------+ | | +-----+------+ |
| | | | | |
| | | | | |
| +-----+------+ | | +-----+------+ |
| | | | | | | |
| | ELF | | | | runtime | |
| | | | | | | |
| +------------+ | | +------------+ |
| | | |
| client | | solana |
+---------------------+ +---------------------+
[Figure 1. Smart Contracts Stack]
In Figure 1 an untrusted client, creates a program in the front-end language of her choice, (like C/C++/Rust/Lua), and compiles it with LLVM to a position independent shared object ELF, targeting BPF bytecode. Solana will safely load and execute the ELF.
## Runtime
The goal with the runtime is to have a general purpose execution environment that is highly parallelizeable and doesn't require dynamic resource management. The goal is to execute as many contracts as possible in parallel, and have them pass or fail without a destructive state change.
### State
State is addressed by an account which is at the moment simply the Pubkey. Our goal is to eliminate memory allocation from within the smart contract itself. Thus the client of the contract provides all the state that is necessary for the contract to execute in the transaction itself. The runtime interacts with the contract through a state transition function, which takes a mapping of [(Pubkey,State)] and returns [(Pubkey, State')]. The State is an opeque type to the runtime, a `Vec<u8>`, the contents of which the contract has full control over.
/// This vector contains a tuple of signatures, and the key index the signature is for
/// proofs[0] is always key[0]
pub proofs: Vec<Signature>,
pub data: CallData,
}
```
At it's core, this is just a set of Pubkeys and Signatures with a bit of metadata. The contract Pubkey routes this transaction into that contracts entry point. `version` is used for dropping retransmitted requests.
Contracts should be able to read any state that is part of runtime, but only write to state that the contract allocated.
At the `execute` stage, the loaded pages have no data dependencies, so all the contracts can be executed in parallel.
## Memory Management
```
pub struct Page {
/// key that indexes this page
/// prove ownership of this key to spend from this Page
owner: Pubkey,
/// contract that owns this page
/// contract can write to the data that is in `memory` vector
contract: Pubkey,
/// balance that belongs to owner
balance: u64,
/// version of the structure, public for testing
version: u64,
/// hash of the page data
memhash: Hash,
/// The following could be in a separate structure
memory: Vec<u8>,
}
```
The guarantee that runtime enforces:
1. The contract code is the only code that will modify the contents of `memory`
2. Total balances on all the pages is equal before and after exectuion of a call
3. Balances of each of the pages not owned by the contract must be equal to or greater after the call than before the call.
## Entry Point
Exectuion of the contract involves maping the contract's public key to an entry point which takes a pointer to the transaction, and an array of loaded pages.
The first 127 methods are reserved for the system interface, which implements allocation and assignment of memory. The rest, including the contract for moving funds are implemented by the contract itself.
## System Interface
```
/// SYSTEM interface, same for very contract, methods 0 to 127
/// method 0
/// reallocate
/// spend the funds from the call to the first recipient's
let contract = deserialize(&call.userdata).unwrap();
if call.contract == DEFAULT_CONTRACT {
pages[0].contract = contract;
//zero out the memory in pages[0].memory
//Contracts need to own the state of that data otherwise a use could fabricate the state and
//manipulate the contract
pages[0].memory.clear();
}
}
```
The first method resizes the memory that is assosciated with the callers page. The second system call assignes the page to the contract. Both methods check if the current contract is 0, otherwise the method does nothing and the caller spent their fees.
This ensures that when memory is assigned to the contract the initial state of all the bytes is 0, and the contract itself is the only thing that can modify that state.
## Simplest contract
```
/// DEFAULT_CONTRACT interface
/// All contracts start with 128
/// method 128
/// move_funds
/// spend the funds from the call to the first recipient's
The goal of this RFC is to define the consensus algorithm used in solana. This proposal covers a Proof of Stake algorithm that leverages Proof of History. PoH is a permissionless clock for blockchain that is available before consensus. This PoS approach leverages PoH to make strong assumptions about time between partitions.
## Version
version 0.1
## Message Flow
1. Transactions are ingested at the leader.
2. Leader filters for valid transactions
3. Leader executes valid transactions on its state
4. Leader packages transactions into blobs
5. Leader transmits blobs to validator nodes.
a. The set of supermajority + `M` by stake weight of nodes is rotated in round robin fashion.
6. Validators retransmit blobs to peers in their set and to further downstream nodes.
7. Validators validate the transactions and execute them on their state.
8. Validators compute the hash of the state.
9. Validators transmit votes to the leader.
a. Votes are signatures of the hash of the computed state.
10. Leader executes the votes as any other transaction and broadcasts them out to the network
11. Validators observe their votes, and all the votes from the network.
12. Validators continue voting if the supermajority of stake is observed in the vote for the same hash.
Supermajority is defined as `2/3rds + 1` vote of the PoS stakes.
## Staking
Validators `stake` some of their spendable sol into a staking account. The stakes are not spendable and can only be used for voting.
```
CreateStake(
PoH count,
PoH hash,
source public key,
amount,
destination public key,
proof of ownership of destination public key,
signature of the message with the source keypair
)
```
Creating the stake has a warmup period of TBD. Unstaking requires the node to miss a certain amount of validation votes.
## Validation Votes
```
Validate(
PoH count,
PoH hash,
stake public key,
signature of the state,
signature of the message with the stake keypair
)
```
## Validator Slashing
Validators `stake` some of their spendable sol into a staking account. The stakes are not spendable and can only be used for voting.
```
Slash(Validate(
PoH count,
PoH hash,
stake public key,
...
signature of the message with the stake keypair
))
```
When the `Slash` vote is processed, validators should lookup `PoH hash` at `PoH count` and compare it with the message. If they do not match, the stake at `stake public key` should be set to `0`.
## Leader Slashing
TBD. The goal of this is to discourage leaders from generating multiple PoH streams.
## Validation Vote Contract
The goal of this contract is to simulate economic cost of mining on a shorter branch.
1. With my signature I am certifying that I computed `state hash` at `PoH count` and `PoH hash`.
2. I will not vote on a branch that doesn't contain this message for at least `N` counts, or until `PoH count` + `N` is reached by the PoH stream.
3. I will not vote for any other branch below `PoH count`.
a. if there are other votes not present in this PoH history the validator may need to `cancel` them before creating this vote.
## Leader Seed Generation
Leader selection is decided via a random seed. The process is as follows:
1. Periodically at a specific `PoH count` select the first vote signatures that create a supermajority from the previous round.
2. append them together
3. hash the string for `N` counts via a similar process as PoH itself.
4. The resulting hash is the random seed for `M` counts, where M > N
## Leader Ranking and Rotation
Leader's transmit for a count of `T`. When `T` is reached all the validators should switch to the next ranked leader. To rank leaders, the supermajority + `M` nodes are shuffled with the using the above calculated random seed.
TBD: define a ranking for critical partitions without a node from supermajority + `M` set.
## Partition selection
Validators should select the first branch to reach finality, or the highest ranking leader.
## Examples
### Small Partition
1. Network partition M occurs for 10% of the nodes
2. The larger partition K, with 90% of the stake weight continues to operate as normal
3. M cycles through the ranks until one of them is leader.
4. M validators observe 10% of the vote pool, finality is not reached
5. M and K re-connect.
6. M validators cancel their votes on K which are below K's `PoH count`
### Leader Timeout
1. Next rank node observes a timeout.
2. Nodes receiving both PoH streams pick the higher rank node.
3. 2, causes a partition, since nodes can only vote for 1 leader.
4. Partition is resolved just like in the [Small Partition](#small-parition)
The goal of this RFC is to define a protocol for storing a very large ledger over a p2p network that is verified by solana validators. At full capacity on a 1gbps network solana will generate 4 petabytes of data per year. To prevent the network from centralizing around full nodes that have to store the full data set this protocol proposes a way for mining nodes to provide storage capacity for pieces of the network.
# Version
version 0.1
# Background
The basic idea to Proof of Replication is encrypting a dataset with a public symmetric key using CBC encryption, then hash the encrypted dataset. The main problem with the naive approach is that a dishonest storage node can stream the encryption and delete the data as its hashed. The simple solution is to force the hash to be done on the reverse of the encryption, or perhaps with a random order. This ensures that all the data is present during the generation of the proof and it also requires the validator to have the entirety of the encrypted data present for verification of every proof of every identity. So the space required to validate is `(Number of Proofs)*(data size)`
# Optimization with PoH
Our improvement on this approach is to randomly sample the encrypted blocks faster than it takes to encrypt, and record the hash of those samples into the PoH ledger. Thus the blocks stay in the exact same order for every PoRep and verification can stream the data and verify all the proofs in a single batch. This way we can verify multiple proofs concurrently, each one on its own CUDA core. With the current generation of graphics cards our network can support up to 14k replication identities or symmetric keys. The total space required for verification is `(2 CBC blocks) * (Number of Identities)`, with core count of equal to (Number of Identities). A CBC block is expected to be 1MB in size.
# Network
Validators for PoRep are the same validators that are verifying transactions. They have some stake that they have put up as collateral that ensures that their work is honest. If you can prove that a validator verified a fake PoRep, then the validators stake can be slashed.
Replicators are specialized thin clients. They download a part of the ledger and store it, and provide PoReps of storing the ledger. For each verified PoRep replicators earn a reward of sol from the mining pool.
# Constraints
We have the following constraints:
* At most 14k replication identities can be used, because thats how many CUDA cores we can fit in a $5k box at the moment.
* Verification requires generating the CBC blocks. That requires space of 2 blocks per identity, and 1 CUDA core per identity for the same dataset. So as many identities at once should be batched with as many proofs for those identities verified concurrently for the same dataset.
# Validation and Replication Protocol
1. Network sets the replication target number, lets say 1k. 1k PoRep identities are created from signatures of a PoH hash. So they are tied to a specific PoH hash. It doesn't matter who creates them, or simply the last 1k validation signatures we saw for the ledger at that count. This maybe just the initial batch of identities, because we want to stagger identity rotation.
2. Any client can use any of these identities to create PoRep proofs. Replicator identities are the CBC encryption keys.
3. Periodically at a specific PoH count, replicator that want to create PoRep proofs sign the PoH hash at that count. That signature is the seed used to pick the block and identity to replicate. A block is 1TB of ledger.
4. Periodically at a specific PoH count, replicator submits PoRep proofs for their selected block. A signature of the PoH hash at that count is the seed used to sample the 1TB encrypted block, and hash it. This is done faster than it takes to encrypt the 1TB block with the original identity.
5. Replicators must submit some number of fake proofs, which they can prove to be fake by providing the seed for the hash result.
6. Periodically at a specific PoH count, validators sign the hash and use the signature to select the 1TB block that they need to validate. They batch all the identities and proofs and submit approval for all the verified ones.
7. After #6, replicator client submit the proofs of fake proofs.
For any random seed, we force everyone to use a signature that is derived from a PoH hash. Everyone must use the same count, so the same PoH hash is signed by every participant. The signatures are then each cryptographically tied to the keypair, which prevents a leader from grinding on the resulting value for more than 1 identity.
We need to stagger the rotation of the identity keys. Once this gets going, the next identity could be generated by hashing itself with a PoH hash, or via some other process based on the validation signatures.
Since there are many more client identities then encryption identities, we need to split the reward for multiple clients, and prevent Sybil attacks from generating many clients to acquire the same block of data. To remain BFT we want to avoid a single human entity from storing all the replications of a single chunk of the ledger.
Our solution to this is to force the clients to continue using the same identity. If the first round is used to acquire the same block for many client identities, the second round for the same client identities will force a redistribution of the signatures, and therefore PoRep identities and blocks. Thus to get a reward for storage clients need to store the first block for free and the network can reward long lived client identities more than new ones.
# Notes
* We can reduce the costs of verification of PoRep by using PoH, and actually make it feasible to verify a large number of proofs for a global dataset.
* We can eliminate grinding by forcing everyone to sign the same PoH hash and use the signatures as the seed
* The game between validators and replicators is over random blocks and random encryption identities and random data samples. The goal of randomization is to prevent colluding groups from having overlap on data or validation.
* Replicator clients fish for lazy validators by submitting fake proofs that they can prove are fake.
* Replication identities are just symmetric encryption keys, the number of them on the network is our storage replication target. Many more client identities can exist than replicator identities, so unlimited number of clients can provide proofs of the same replicator identity.
* To defend against Sybil client identities that try to store the same block we force the clients to store for multiple rounds before receiving a reward.
echo"Failed to set oom_score_adj to $score for pid $pid (current score: $currentScore)"
fi
}
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.