diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000000..2f7896d1d1
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1 @@
+target/
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
deleted file mode 100644
index c2fc36a3e6..0000000000
--- a/.github/dependabot.yml
+++ /dev/null
@@ -1,41 +0,0 @@
-# To get started with Dependabot version updates, you'll need to specify which
-# package ecosystems to update and where the package manifests are located.
-# Please see the documentation for all configuration options:
-# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
-
-version: 2
-updates:
-- package-ecosystem: cargo
- directory: "/"
- schedule:
- interval: daily
- time: "01:00"
- timezone: America/Los_Angeles
- #labels:
- # - "automerge"
- open-pull-requests-limit: 3
-
-- package-ecosystem: npm
- directory: "/web3.js"
- schedule:
- interval: daily
- time: "01:00"
- timezone: America/Los_Angeles
- labels:
- - "automerge"
- commit-message:
- prefix: "chore:"
- open-pull-requests-limit: 3
-
-- package-ecosystem: npm
- directory: "/explorer"
- schedule:
- interval: daily
- time: "01:00"
- timezone: America/Los_Angeles
- labels:
- - "automerge"
- commit-message:
- prefix: "chore:"
- include: "scope"
- open-pull-requests-limit: 3
diff --git a/.github/workflows/client-targets.yml b/.github/workflows/client-targets.yml
index c5c8532461..8e4448ca39 100644
--- a/.github/workflows/client-targets.yml
+++ b/.github/workflows/client-targets.yml
@@ -45,8 +45,10 @@ jobs:
platform: android
os: ubuntu-latest
steps:
- - name: Checkout code
- uses: actions/checkout@v2
+ - uses: actions/checkout@v3
+ with:
+ submodules: recursive
+ ssh-key: ${{ secrets.DEPLOYER_SSH_KEY }}
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
diff --git a/.gitignore b/.gitignore
index 124358b46f..92281a9a08 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,7 +3,7 @@
/solana-release.tar.bz2
/solana-metrics/
/solana-metrics.tar.bz2
-/target/
+**/target/
/test-ledger/
**/*.rs.bk
@@ -30,3 +30,6 @@ log-*/
.DS_Store
# scripts that may be generated by cargo *-bpf commands
**/cargo-*-bpf-child-script-*.sh
+
+.env
+docker-output/
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000000..e31fc7fccd
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,9 @@
+[submodule "anchor"]
+ path = anchor
+ url = https://github.com/jito-foundation/anchor.git
+[submodule "jito-programs"]
+ path = jito-programs
+ url = https://github.com/jito-foundation/jito-programs.git
+[submodule "jito-protos/protos"]
+ path = jito-protos/protos
+ url = https://github.com/jito-labs/mev-protos.git
diff --git a/Cargo.lock b/Cargo.lock
index 5d1f0f16f0..66a9a9c518 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -95,6 +95,145 @@ dependencies = [
"alloc-no-stdlib",
]
+[[package]]
+name = "anchor-attribute-access-control"
+version = "0.24.2"
+dependencies = [
+ "anchor-syn",
+ "anyhow",
+ "proc-macro2 1.0.52",
+ "quote 1.0.18",
+ "regex",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "anchor-attribute-account"
+version = "0.24.2"
+dependencies = [
+ "anchor-syn",
+ "anyhow",
+ "bs58 0.4.0",
+ "proc-macro2 1.0.52",
+ "quote 1.0.18",
+ "rustversion",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "anchor-attribute-constant"
+version = "0.24.2"
+dependencies = [
+ "anchor-syn",
+ "proc-macro2 1.0.52",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "anchor-attribute-error"
+version = "0.24.2"
+dependencies = [
+ "anchor-syn",
+ "proc-macro2 1.0.52",
+ "quote 1.0.18",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "anchor-attribute-event"
+version = "0.24.2"
+dependencies = [
+ "anchor-syn",
+ "anyhow",
+ "proc-macro2 1.0.52",
+ "quote 1.0.18",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "anchor-attribute-interface"
+version = "0.24.2"
+dependencies = [
+ "anchor-syn",
+ "anyhow",
+ "heck 0.3.3",
+ "proc-macro2 1.0.52",
+ "quote 1.0.18",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "anchor-attribute-program"
+version = "0.24.2"
+dependencies = [
+ "anchor-syn",
+ "anyhow",
+ "proc-macro2 1.0.52",
+ "quote 1.0.18",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "anchor-attribute-state"
+version = "0.24.2"
+dependencies = [
+ "anchor-syn",
+ "anyhow",
+ "proc-macro2 1.0.52",
+ "quote 1.0.18",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "anchor-derive-accounts"
+version = "0.24.2"
+dependencies = [
+ "anchor-syn",
+ "anyhow",
+ "proc-macro2 1.0.52",
+ "quote 1.0.18",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "anchor-lang"
+version = "0.24.2"
+dependencies = [
+ "anchor-attribute-access-control",
+ "anchor-attribute-account",
+ "anchor-attribute-constant",
+ "anchor-attribute-error",
+ "anchor-attribute-event",
+ "anchor-attribute-interface",
+ "anchor-attribute-program",
+ "anchor-attribute-state",
+ "anchor-derive-accounts",
+ "arrayref",
+ "base64 0.13.0",
+ "bincode",
+ "borsh",
+ "bytemuck",
+ "solana-program 1.14.19",
+ "thiserror",
+]
+
+[[package]]
+name = "anchor-syn"
+version = "0.24.2"
+dependencies = [
+ "anyhow",
+ "bs58 0.3.1",
+ "heck 0.3.3",
+ "proc-macro2 1.0.52",
+ "proc-macro2-diagnostics",
+ "quote 1.0.18",
+ "serde",
+ "serde_json",
+ "sha2 0.9.9",
+ "syn 1.0.109",
+ "thiserror",
+]
+
[[package]]
name = "ansi_term"
version = "0.11.0"
@@ -535,6 +674,12 @@ dependencies = [
"alloc-stdlib",
]
+[[package]]
+name = "bs58"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "476e9cd489f9e121e02ffa6014a8ef220ecb15c05ed23fc34cca13925dc283fb"
+
[[package]]
name = "bs58"
version = "0.4.0"
@@ -1531,6 +1676,12 @@ dependencies = [
"winapi 0.3.9",
]
+[[package]]
+name = "fixedbitset"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d"
+
[[package]]
name = "fixedbitset"
version = "0.4.0"
@@ -2241,6 +2392,28 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
+[[package]]
+name = "jito-programs-vote-state"
+version = "0.1.2"
+dependencies = [
+ "anchor-lang",
+ "bincode",
+ "serde",
+ "serde_derive",
+ "solana-program 1.14.19",
+]
+
+[[package]]
+name = "jito-protos"
+version = "1.14.19"
+dependencies = [
+ "bytes",
+ "prost 0.8.0",
+ "prost-types 0.8.0",
+ "tonic 0.5.2",
+ "tonic-build 0.5.2",
+]
+
[[package]]
name = "jobserver"
version = "0.1.24"
@@ -3204,13 +3377,23 @@ dependencies = [
"sha-1 0.8.2",
]
+[[package]]
+name = "petgraph"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7"
+dependencies = [
+ "fixedbitset 0.2.0",
+ "indexmap",
+]
+
[[package]]
name = "petgraph"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a13a2fa9d0b63e5f22328828741e523766fff0ee9e779316902290dff3f824f"
dependencies = [
- "fixedbitset",
+ "fixedbitset 0.4.0",
"indexmap",
]
@@ -3401,6 +3584,19 @@ dependencies = [
"unicode-ident",
]
+[[package]]
+name = "proc-macro2-diagnostics"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4bf29726d67464d49fa6224a1d07936a8c08bb3fba727c7493f6cf1616fdaada"
+dependencies = [
+ "proc-macro2 1.0.52",
+ "quote 1.0.18",
+ "syn 1.0.109",
+ "version_check",
+ "yansi",
+]
+
[[package]]
name = "proptest"
version = "1.0.0"
@@ -3421,6 +3617,16 @@ dependencies = [
"tempfile",
]
+[[package]]
+name = "prost"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "de5e2533f59d08fcf364fd374ebda0692a70bd6d7e66ef97f306f45c6c5d8020"
+dependencies = [
+ "bytes",
+ "prost-derive 0.8.0",
+]
+
[[package]]
name = "prost"
version = "0.9.0"
@@ -3441,6 +3647,24 @@ dependencies = [
"prost-derive 0.11.0",
]
+[[package]]
+name = "prost-build"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "355f634b43cdd80724ee7848f95770e7e70eefa6dcf14fea676216573b8fd603"
+dependencies = [
+ "bytes",
+ "heck 0.3.3",
+ "itertools",
+ "log",
+ "multimap",
+ "petgraph 0.5.1",
+ "prost 0.8.0",
+ "prost-types 0.8.0",
+ "tempfile",
+ "which",
+]
+
[[package]]
name = "prost-build"
version = "0.9.0"
@@ -3453,7 +3677,7 @@ dependencies = [
"lazy_static",
"log",
"multimap",
- "petgraph",
+ "petgraph 0.6.0",
"prost 0.9.0",
"prost-types 0.9.0",
"regex",
@@ -3473,7 +3697,7 @@ dependencies = [
"lazy_static",
"log",
"multimap",
- "petgraph",
+ "petgraph 0.6.0",
"prost 0.11.0",
"prost-types 0.11.0",
"regex",
@@ -3481,6 +3705,19 @@ dependencies = [
"which",
]
+[[package]]
+name = "prost-derive"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "600d2f334aa05acb02a755e217ef1ab6dea4d51b58b7846588b747edec04efba"
+dependencies = [
+ "anyhow",
+ "itertools",
+ "proc-macro2 1.0.52",
+ "quote 1.0.18",
+ "syn 1.0.109",
+]
+
[[package]]
name = "prost-derive"
version = "0.9.0"
@@ -3507,6 +3744,16 @@ dependencies = [
"syn 1.0.109",
]
+[[package]]
+name = "prost-types"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "603bbd6394701d13f3f25aada59c7de9d35a6a5887cfc156181234a44002771b"
+dependencies = [
+ "bytes",
+ "prost 0.8.0",
+]
+
[[package]]
name = "prost-types"
version = "0.9.0"
@@ -3595,7 +3842,7 @@ dependencies = [
"rand 0.8.5",
"ring",
"rustls 0.20.6",
- "rustls-native-certs",
+ "rustls-native-certs 0.6.1",
"rustls-pemfile 0.2.1",
"slab",
"thiserror",
@@ -3925,7 +4172,7 @@ dependencies = [
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
- "webpki-roots",
+ "webpki-roots 0.22.1",
"winreg",
]
@@ -4058,6 +4305,18 @@ dependencies = [
"webpki 0.22.0",
]
+[[package]]
+name = "rustls-native-certs"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a07b7c1885bd8ed3831c289b7870b13ef46fe0e856d288c30d9cc17d75a2092"
+dependencies = [
+ "openssl-probe",
+ "rustls 0.19.1",
+ "schannel",
+ "security-framework",
+]
+
[[package]]
name = "rustls-native-certs"
version = "0.6.1"
@@ -4515,7 +4774,7 @@ dependencies = [
"Inflector",
"base64 0.13.0",
"bincode",
- "bs58",
+ "bs58 0.4.0",
"bv",
"lazy_static",
"serde",
@@ -4660,9 +4919,11 @@ dependencies = [
"futures 0.3.21",
"solana-banks-interface",
"solana-client",
+ "solana-gossip",
"solana-runtime",
"solana-sdk 1.14.19",
"solana-send-transaction-service",
+ "solana-streamer",
"tarpc",
"tokio",
"tokio-serde",
@@ -4855,7 +5116,7 @@ name = "solana-cli"
version = "1.14.19"
dependencies = [
"bincode",
- "bs58",
+ "bs58 0.4.0",
"clap 2.33.3",
"console",
"const_format",
@@ -4947,7 +5208,7 @@ dependencies = [
"async-trait",
"base64 0.13.0",
"bincode",
- "bs58",
+ "bs58 0.4.0",
"bytes",
"clap 2.33.3",
"crossbeam-channel",
@@ -5046,23 +5307,33 @@ name = "solana-core"
version = "1.14.19"
dependencies = [
"ahash",
+ "anchor-lang",
"base64 0.13.0",
"bincode",
- "bs58",
+ "bs58 0.4.0",
+ "bytes",
"chrono",
+ "clap 3.2.23",
"crossbeam-channel",
"dashmap",
"eager",
"etcd-client",
"fs_extra",
+ "futures 0.3.21",
+ "futures-util",
+ "h2",
"histogram",
+ "indexmap",
"itertools",
+ "jito-protos",
"lazy_static",
"log",
"lru",
"matches",
"min-max-heap",
"num_enum",
+ "prost 0.8.0",
+ "prost-types 0.8.0",
"rand 0.7.3",
"rand_chacha 0.2.2",
"raptorq",
@@ -5105,7 +5376,12 @@ dependencies = [
"tempfile",
"test-case",
"thiserror",
+ "tip-distribution",
+ "tip-payment",
"tokio",
+ "tokio-stream",
+ "tonic 0.5.2",
+ "tonic-build 0.5.2",
"trees",
]
@@ -5214,7 +5490,7 @@ dependencies = [
"ahash",
"blake3",
"block-buffer 0.9.0",
- "bs58",
+ "bs58 0.4.0",
"bv",
"byteorder",
"cc",
@@ -5246,7 +5522,7 @@ dependencies = [
"ahash",
"blake3",
"block-buffer 0.9.0",
- "bs58",
+ "bs58 0.4.0",
"bv",
"byteorder",
"cc",
@@ -5339,7 +5615,7 @@ dependencies = [
name = "solana-geyser-plugin-manager"
version = "1.14.19"
dependencies = [
- "bs58",
+ "bs58 0.4.0",
"crossbeam-channel",
"json5",
"libloading",
@@ -5438,7 +5714,7 @@ dependencies = [
name = "solana-keygen"
version = "1.14.19"
dependencies = [
- "bs58",
+ "bs58 0.4.0",
"clap 3.2.23",
"dirs-next",
"num_cpus",
@@ -5457,7 +5733,7 @@ dependencies = [
"assert_matches",
"bincode",
"bitflags",
- "bs58",
+ "bs58 0.4.0",
"byteorder",
"chrono",
"chrono-humanize",
@@ -5775,7 +6051,7 @@ dependencies = [
"blake3",
"borsh",
"borsh-derive",
- "bs58",
+ "bs58 0.4.0",
"bv",
"bytemuck",
"cc",
@@ -5824,7 +6100,7 @@ dependencies = [
"blake3",
"borsh",
"borsh-derive",
- "bs58",
+ "bs58 0.4.0",
"bv",
"bytemuck",
"cc",
@@ -5945,7 +6221,7 @@ version = "1.14.19"
dependencies = [
"base64 0.13.0",
"bincode",
- "bs58",
+ "bs58 0.4.0",
"crossbeam-channel",
"dashmap",
"itertools",
@@ -5999,7 +6275,7 @@ name = "solana-rpc-test"
version = "1.14.19"
dependencies = [
"bincode",
- "bs58",
+ "bs58 0.4.0",
"crossbeam-channel",
"futures-util",
"log",
@@ -6092,7 +6368,7 @@ dependencies = [
"bincode",
"bitflags",
"borsh",
- "bs58",
+ "bs58 0.4.0",
"bytemuck",
"byteorder",
"chrono",
@@ -6136,13 +6412,14 @@ dependencies = [
name = "solana-sdk"
version = "1.14.19"
dependencies = [
+ "anchor-lang",
"anyhow",
"assert_matches",
"base64 0.13.0",
"bincode",
"bitflags",
"borsh",
- "bs58",
+ "bs58 0.4.0",
"bytemuck",
"byteorder",
"chrono",
@@ -6192,7 +6469,7 @@ version = "1.14.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d41a09b9cecd0a4df63c78a192adee99ebf2d3757c19713a68246e1d9789c7c"
dependencies = [
- "bs58",
+ "bs58 0.4.0",
"proc-macro2 1.0.52",
"quote 1.0.18",
"rustversion",
@@ -6203,7 +6480,7 @@ dependencies = [
name = "solana-sdk-macro"
version = "1.14.19"
dependencies = [
- "bs58",
+ "bs58 0.4.0",
"proc-macro2 1.0.52",
"quote 1.0.18",
"rustversion",
@@ -6217,11 +6494,13 @@ dependencies = [
"crossbeam-channel",
"log",
"solana-client",
+ "solana-gossip",
"solana-logger 1.14.19",
"solana-measure",
"solana-metrics",
"solana-runtime",
"solana-sdk 1.14.19",
+ "solana-streamer",
]
[[package]]
@@ -6300,7 +6579,7 @@ name = "solana-storage-proto"
version = "1.14.19"
dependencies = [
"bincode",
- "bs58",
+ "bs58 0.4.0",
"enum-iterator",
"prost 0.11.0",
"protobuf-src",
@@ -6389,6 +6668,35 @@ dependencies = [
"tokio",
]
+[[package]]
+name = "solana-tip-distributor"
+version = "1.14.19"
+dependencies = [
+ "anchor-lang",
+ "clap 3.2.23",
+ "env_logger",
+ "futures 0.3.21",
+ "im",
+ "itertools",
+ "log",
+ "num-traits",
+ "serde",
+ "serde_json",
+ "solana-client",
+ "solana-genesis-utils",
+ "solana-ledger",
+ "solana-merkle-tree",
+ "solana-program 1.14.19",
+ "solana-rpc",
+ "solana-runtime",
+ "solana-sdk 1.14.19",
+ "solana-stake-program",
+ "thiserror",
+ "tip-distribution",
+ "tip-payment",
+ "tokio",
+]
+
[[package]]
name = "solana-tokens"
version = "1.14.19"
@@ -6454,7 +6762,7 @@ dependencies = [
"base64 0.13.0",
"bincode",
"borsh",
- "bs58",
+ "bs58 0.4.0",
"lazy_static",
"log",
"serde",
@@ -6530,6 +6838,7 @@ dependencies = [
"solana-vote-program",
"symlink",
"tikv-jemallocator",
+ "tonic 0.5.2",
]
[[package]]
@@ -7154,6 +7463,22 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
+[[package]]
+name = "tip-distribution"
+version = "0.1.0"
+dependencies = [
+ "anchor-lang",
+ "jito-programs-vote-state",
+ "solana-program 1.14.19",
+]
+
+[[package]]
+name = "tip-payment"
+version = "0.1.0"
+dependencies = [
+ "anchor-lang",
+]
+
[[package]]
name = "tokio"
version = "1.14.1"
@@ -7267,7 +7592,7 @@ dependencies = [
"tokio-rustls 0.23.3",
"tungstenite",
"webpki 0.22.0",
- "webpki-roots",
+ "webpki-roots 0.22.1",
]
[[package]]
@@ -7309,6 +7634,40 @@ dependencies = [
"serde",
]
+[[package]]
+name = "tonic"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "796c5e1cd49905e65dd8e700d4cb1dffcbfdb4fc9d017de08c1a537afd83627c"
+dependencies = [
+ "async-stream",
+ "async-trait",
+ "base64 0.13.0",
+ "bytes",
+ "futures-core",
+ "futures-util",
+ "h2",
+ "http",
+ "http-body",
+ "hyper",
+ "hyper-timeout",
+ "percent-encoding 2.1.0",
+ "pin-project",
+ "prost 0.8.0",
+ "prost-derive 0.8.0",
+ "rustls-native-certs 0.5.0",
+ "tokio",
+ "tokio-rustls 0.22.0",
+ "tokio-stream",
+ "tokio-util 0.6.9",
+ "tower",
+ "tower-layer",
+ "tower-service",
+ "tracing",
+ "tracing-futures",
+ "webpki-roots 0.21.1",
+]
+
[[package]]
name = "tonic"
version = "0.6.2"
@@ -7375,6 +7734,18 @@ dependencies = [
"tracing-futures",
]
+[[package]]
+name = "tonic-build"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "12b52d07035516c2b74337d2ac7746075e7dcae7643816c1b12c5ff8a7484c08"
+dependencies = [
+ "proc-macro2 1.0.52",
+ "prost-build 0.8.0",
+ "quote 1.0.18",
+ "syn 1.0.109",
+]
+
[[package]]
name = "tonic-build"
version = "0.6.2"
@@ -7548,7 +7919,7 @@ dependencies = [
"url 2.2.2",
"utf-8",
"webpki 0.22.0",
- "webpki-roots",
+ "webpki-roots 0.22.1",
]
[[package]]
@@ -7868,6 +8239,15 @@ dependencies = [
"untrusted",
]
+[[package]]
+name = "webpki-roots"
+version = "0.21.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940"
+dependencies = [
+ "webpki 0.21.4",
+]
+
[[package]]
name = "webpki-roots"
version = "0.22.1"
@@ -8128,6 +8508,12 @@ dependencies = [
"linked-hash-map",
]
+[[package]]
+name = "yansi"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
+
[[package]]
name = "yasna"
version = "0.5.0"
diff --git a/Cargo.toml b/Cargo.toml
index 219a27a411..f27d9528c6 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -30,6 +30,7 @@ members = [
"geyser-plugin-manager",
"gossip",
"install",
+ "jito-protos",
"keygen",
"ledger",
"ledger-tool",
@@ -80,6 +81,7 @@ members = [
"streamer",
"sys-tuner",
"test-validator",
+ "tip-distributor",
"tokens",
"transaction-dos",
"transaction-status",
@@ -91,6 +93,8 @@ members = [
]
exclude = [
+ "anchor",
+ "jito-programs",
"programs/bpf",
]
diff --git a/README.md b/README.md
index 0e939f533f..81863bae57 100644
--- a/README.md
+++ b/README.md
@@ -4,10 +4,14 @@
-[![Solana crate](https://img.shields.io/crates/v/solana-core.svg)](https://crates.io/crates/solana-core)
-[![Solana documentation](https://docs.rs/solana-core/badge.svg)](https://docs.rs/solana-core)
-[![Build status](https://badge.buildkite.com/8cc350de251d61483db98bdfc895b9ea0ac8ffa4a32ee850ed.svg?branch=master)](https://buildkite.com/solana-labs/solana/builds?branch=master)
-[![codecov](https://codecov.io/gh/solana-labs/solana/branch/master/graph/badge.svg)](https://codecov.io/gh/solana-labs/solana)
+[![Build status](https://badge.buildkite.com/a6981eb34c6e0c7c09e3a3cb4bda09579f0ff2dcb1bd74b2ad.svg?branch=master)](https://buildkite.com/jito-labs/jito-solana)
+
+[//]: # ([![Solana crate](https://img.shields.io/crates/v/solana-core.svg)](https://crates.io/crates/solana-core))
+[//]: # ([![Solana documentation](https://docs.rs/solana-core/badge.svg)](https://docs.rs/solana-core))
+[//]: # ([![codecov](https://codecov.io/gh/solana-labs/solana/branch/master/graph/badge.svg)](https://codecov.io/gh/solana-labs/solana))
+
+# About
+This repository contains Jito Foundations's fork of the Solana validator.
# Building
diff --git a/anchor b/anchor
new file mode 160000
index 0000000000..25a497e4f0
--- /dev/null
+++ b/anchor
@@ -0,0 +1 @@
+Subproject commit 25a497e4f0f300eb363b44a52f5c794e7085b0f4
diff --git a/banking-bench/src/main.rs b/banking-bench/src/main.rs
index 2806a8a9e0..64a19c289a 100644
--- a/banking-bench/src/main.rs
+++ b/banking-bench/src/main.rs
@@ -6,7 +6,7 @@ use {
rand::{thread_rng, Rng},
rayon::prelude::*,
solana_client::connection_cache::{ConnectionCache, DEFAULT_TPU_CONNECTION_POOL_SIZE},
- solana_core::banking_stage::BankingStage,
+ solana_core::{banking_stage::BankingStage, bundle_account_locker::BundleAccountLocker},
solana_gossip::cluster_info::{ClusterInfo, Node},
solana_ledger::{
blockstore::Blockstore,
@@ -30,6 +30,7 @@ use {
},
solana_streamer::socket::SocketAddrSpace,
std::{
+ collections::HashSet,
sync::{atomic::Ordering, Arc, RwLock},
thread::sleep,
time::{Duration, Instant},
@@ -45,9 +46,15 @@ fn check_txs(
let now = Instant::now();
let mut no_bank = false;
loop {
- if let Ok((_bank, (entry, _tick_height))) = receiver.recv_timeout(Duration::from_millis(10))
+ if let Ok(WorkingBankEntry {
+ bank: _,
+ entries_ticks,
+ }) = receiver.recv_timeout(Duration::from_millis(10))
{
- total += entry.transactions.len();
+ total += entries_ticks
+ .iter()
+ .map(|e| e.0.transactions.len())
+ .sum::();
}
if total >= ref_tx_count {
break;
@@ -359,6 +366,8 @@ fn main() {
None,
Arc::new(connection_cache),
bank_forks.clone(),
+ HashSet::default(),
+ BundleAccountLocker::default(),
);
poh_recorder.write().unwrap().set_bank(&bank, false);
diff --git a/banks-server/Cargo.toml b/banks-server/Cargo.toml
index c4c60cb7fd..a49bd5075f 100644
--- a/banks-server/Cargo.toml
+++ b/banks-server/Cargo.toml
@@ -15,6 +15,7 @@ crossbeam-channel = "0.5"
futures = "0.3"
solana-banks-interface = { path = "../banks-interface", version = "=1.14.19" }
solana-client = { path = "../client", version = "=1.14.19" }
+solana-gossip = { path = "../gossip", version = "=1.14.19" }
solana-runtime = { path = "../runtime", version = "=1.14.19" }
solana-sdk = { path = "../sdk", version = "=1.14.19" }
solana-send-transaction-service = { path = "../send-transaction-service", version = "=1.14.19" }
@@ -23,6 +24,9 @@ tokio = { version = "1", features = ["full"] }
tokio-serde = { version = "0.8", features = ["bincode"] }
tokio-stream = "0.1"
+[dev-dependencies]
+solana-streamer = { path = "../streamer", version = "=1.14.19" }
+
[lib]
crate-type = ["lib"]
name = "solana_banks_server"
diff --git a/banks-server/src/banks_server.rs b/banks-server/src/banks_server.rs
index cf0a1c6083..08a5478781 100644
--- a/banks-server/src/banks_server.rs
+++ b/banks-server/src/banks_server.rs
@@ -7,6 +7,7 @@ use {
TransactionConfirmationStatus, TransactionSimulationDetails, TransactionStatus,
},
solana_client::connection_cache::ConnectionCache,
+ solana_gossip::cluster_info::ClusterInfo,
solana_runtime::{
bank::{Bank, TransactionSimulationResult},
bank_forks::BankForks,
@@ -391,7 +392,7 @@ pub async fn start_local_server(
pub async fn start_tcp_server(
listen_addr: SocketAddr,
- tpu_addr: SocketAddr,
+ cluster_info: Arc,
bank_forks: Arc>,
block_commitment_cache: Arc>,
connection_cache: Arc,
@@ -416,7 +417,7 @@ pub async fn start_tcp_server(
let (sender, receiver) = unbounded();
SendTransactionService::new::(
- tpu_addr,
+ cluster_info.clone(),
&bank_forks,
None,
receiver,
diff --git a/banks-server/src/rpc_banks_service.rs b/banks-server/src/rpc_banks_service.rs
index f3224fb64e..4d4ad61dae 100644
--- a/banks-server/src/rpc_banks_service.rs
+++ b/banks-server/src/rpc_banks_service.rs
@@ -4,6 +4,7 @@ use {
crate::banks_server::start_tcp_server,
futures::{future::FutureExt, pin_mut, prelude::stream::StreamExt, select},
solana_client::connection_cache::ConnectionCache,
+ solana_gossip::cluster_info::ClusterInfo,
solana_runtime::{bank_forks::BankForks, commitment::BlockCommitmentCache},
std::{
net::SocketAddr,
@@ -27,7 +28,7 @@ pub struct RpcBanksService {
/// Run the TCP service until `exit` is set to true
async fn start_abortable_tcp_server(
listen_addr: SocketAddr,
- tpu_addr: SocketAddr,
+ cluster_info: Arc,
bank_forks: Arc>,
block_commitment_cache: Arc>,
connection_cache: Arc,
@@ -35,7 +36,7 @@ async fn start_abortable_tcp_server(
) {
let server = start_tcp_server(
listen_addr,
- tpu_addr,
+ cluster_info,
bank_forks.clone(),
block_commitment_cache.clone(),
connection_cache,
@@ -59,7 +60,7 @@ async fn start_abortable_tcp_server(
impl RpcBanksService {
fn run(
listen_addr: SocketAddr,
- tpu_addr: SocketAddr,
+ cluster_info: Arc,
bank_forks: Arc>,
block_commitment_cache: Arc>,
connection_cache: Arc,
@@ -67,7 +68,7 @@ impl RpcBanksService {
) {
let server = start_abortable_tcp_server(
listen_addr,
- tpu_addr,
+ cluster_info,
bank_forks,
block_commitment_cache,
connection_cache,
@@ -78,7 +79,7 @@ impl RpcBanksService {
pub fn new(
listen_addr: SocketAddr,
- tpu_addr: SocketAddr,
+ cluster_info: Arc,
bank_forks: &Arc>,
block_commitment_cache: &Arc>,
connection_cache: &Arc,
@@ -93,7 +94,7 @@ impl RpcBanksService {
.spawn(move || {
Self::run(
listen_addr,
- tpu_addr,
+ cluster_info,
bank_forks,
block_commitment_cache,
connection_cache,
@@ -112,7 +113,14 @@ impl RpcBanksService {
#[cfg(test)]
mod tests {
- use {super::*, solana_runtime::bank::Bank};
+ use {
+ super::*,
+ solana_gossip::legacy_contact_info::LegacyContactInfo as ContactInfo,
+ solana_runtime::bank::Bank,
+ solana_sdk::signature::Keypair,
+ solana_streamer::socket::SocketAddrSpace,
+ std::net::{IpAddr, Ipv4Addr},
+ };
#[test]
fn test_rpc_banks_server_exit() {
@@ -121,9 +129,18 @@ mod tests {
let connection_cache = Arc::new(ConnectionCache::default());
let exit = Arc::new(AtomicBool::new(false));
let addr = "127.0.0.1:0".parse().unwrap();
+ let contact_info = ContactInfo {
+ tpu: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080),
+ ..ContactInfo::default()
+ };
+ let cluster_info: Arc = Arc::new(ClusterInfo::new(
+ contact_info,
+ Arc::new(Keypair::new()),
+ SocketAddrSpace::new(false),
+ ));
let service = RpcBanksService::new(
addr,
- addr,
+ cluster_info,
&bank_forks,
&block_commitment_cache,
&connection_cache,
diff --git a/bootstrap b/bootstrap
new file mode 100755
index 0000000000..b01bc6734f
--- /dev/null
+++ b/bootstrap
@@ -0,0 +1,21 @@
+#!/usr/bin/env sh
+bank_hash=$(./target/release/solana-ledger-tool -l config/bootstrap-validator bank-hash)
+
+# NOTE: make sure tip-payment and tip-distribution program are deployed using the correct pubkeys
+RUST_LOG=INFO,solana_core::bundle_stage=DEBUG \
+ NDEBUG=1 ./multinode-demo/bootstrap-validator.sh \
+ --wait-for-supermajority 0 \
+ --expected-bank-hash $bank_hash \
+ --block-engine-address http://127.0.0.1:1003 \
+ --block-engine-auth-service-address http://127.0.0.1:1005 \
+ --relayer-auth-service-address http://127.0.0.1:11226 \
+ --relayer-address http://127.0.0.1:11226 \
+ --rpc-pubsub-enable-block-subscription \
+ --enable-rpc-transaction-history \
+ --tip-payment-program-pubkey 6veFRUKJBNGMR58LEcKn5Bc6MR17WZF4rsgD4Lqq7fsU \
+ --tip-distribution-program-pubkey 3PX9z1qPj37eNZqH7e5fyaVDyG7ARqkjkYEe1a4xsBkA \
+ --commission-bps 0 \
+ --shred-receiver-address 127.0.0.1:1002 \
+ --allow-private-addr \
+ --trust-relayer-packets \
+ --trust-block-engine-packets
diff --git a/ci/buildkite-pipeline-in-disk.sh b/ci/buildkite-pipeline-in-disk.sh
index fcb4eb6118..694c2dab46 100644
--- a/ci/buildkite-pipeline-in-disk.sh
+++ b/ci/buildkite-pipeline-in-disk.sh
@@ -185,7 +185,7 @@ all_test_steps() {
queue: "gcp"
EOF
else
- annotate --style info \
+ annotate --style info --context test-stable-bpf \
"Stable-BPF skipped as no relevant files were modified"
fi
@@ -203,16 +203,20 @@ EOF
^programs/ \
^sdk/ \
; then
- cat >> "$output_file" <<"EOF"
- - command: "ci/test-stable-perf.sh"
- name: "stable-perf"
- timeout_in_minutes: 20
- artifact_paths: "log-*.txt"
- agents:
- queue: "cuda"
-EOF
+
+annotate --style warning --context test-stable-perf \
+ "test-stable-perf is currently disabled because it requires GPUs (LB)"
+#cat >> "$output_file" <<"EOF"
+# - command: "ci/test-stable-perf.sh"
+# name: "stable-perf"
+# timeout_in_minutes: 20
+# artifact_paths: "log-*.txt"
+# agents:
+# queue: "cuda"
+#EOF
+
else
- annotate --style info \
+ annotate --style info --context test-stable-perf \
"Stable-perf skipped as no relevant files were modified"
fi
@@ -237,7 +241,7 @@ EOF
timeout_in_minutes: 30
EOF
else
- annotate --style info \
+ annotate --style info --context test-downstream-projects \
"downstream-projects skipped as no relevant files were modified"
fi
@@ -247,9 +251,11 @@ EOF
^ci/test-stable.sh \
^sdk/ \
; then
- command_step wasm ". ci/rust-version.sh; ci/docker-run.sh \$\$rust_stable_docker_image ci/test-wasm.sh" 20
+ annotate --style warning --context test-wasm \
+ "test-wasm is currently disabled because it times out (LB)"
+# command_step wasm ". ci/rust-version.sh; ci/docker-run.sh \$\$rust_stable_docker_image ci/test-wasm.sh" 20
else
- annotate --style info \
+ annotate --style info --context test-wasm \
"wasm skipped as no relevant files were modified"
fi
@@ -312,7 +318,7 @@ if [[ -n $BUILDKITE_TAG ]]; then
"https://github.com/solana-labs/solana/releases/$BUILDKITE_TAG"
# Jump directly to the secondary build to publish release artifacts quickly
- trigger_secondary_step
+# trigger_secondary_step
exit 0
fi
@@ -340,5 +346,5 @@ fi
start_pipeline "Push pipeline for ${BUILDKITE_BRANCH:-?unknown branch?}"
pull_or_push_steps
wait_step
-trigger_secondary_step
+#trigger_secondary_step
exit 0
diff --git a/ci/buildkite-pipeline.sh b/ci/buildkite-pipeline.sh
index 71bdb01b60..a719b14ef4 100755
--- a/ci/buildkite-pipeline.sh
+++ b/ci/buildkite-pipeline.sh
@@ -190,7 +190,7 @@ all_test_steps() {
queue: "solana"
EOF
else
- annotate --style info \
+ annotate --style info --context test-stable-bpf \
"Stable-BPF skipped as no relevant files were modified"
fi
@@ -208,16 +208,20 @@ EOF
^programs/ \
^sdk/ \
; then
- cat >> "$output_file" <<"EOF"
- - command: "ci/test-stable-perf.sh"
- name: "stable-perf"
- timeout_in_minutes: 20
- artifact_paths: "log-*.txt"
- agents:
- queue: "cuda"
-EOF
+
+annotate --style warning --context test-stable-perf \
+ "test-stable-perf is currently disabled because it requires GPUs (LB)"
+#cat >> "$output_file" <<"EOF"
+# - command: "ci/test-stable-perf.sh"
+# name: "stable-perf"
+# timeout_in_minutes: 20
+# artifact_paths: "log-*.txt"
+# agents:
+# queue: "cuda"
+#EOF
+
else
- annotate --style info \
+ annotate --style info --context test-stable-perf \
"Stable-perf skipped as no relevant files were modified"
fi
@@ -244,7 +248,7 @@ EOF
queue: "solana"
EOF
else
- annotate --style info \
+ annotate --style info --context test-downstream-projects \
"downstream-projects skipped as no relevant files were modified"
fi
@@ -254,9 +258,11 @@ EOF
^ci/test-stable.sh \
^sdk/ \
; then
- command_step wasm ". ci/rust-version.sh; ci/docker-run.sh \$\$rust_stable_docker_image ci/test-wasm.sh" 20
+ annotate --style warning --context test-wasm \
+ "test-wasm is currently disabled because it times out (LB)"
+# command_step wasm ". ci/rust-version.sh; ci/docker-run.sh \$\$rust_stable_docker_image ci/test-wasm.sh" 20
else
- annotate --style info \
+ annotate --style info --context test-wasm \
"wasm skipped as no relevant files were modified"
fi
@@ -342,7 +348,7 @@ if [[ -n $BUILDKITE_TAG ]]; then
"https://github.com/solana-labs/solana/releases/$BUILDKITE_TAG"
# Jump directly to the secondary build to publish release artifacts quickly
- trigger_secondary_step
+# trigger_secondary_step
exit 0
fi
@@ -370,5 +376,5 @@ fi
start_pipeline "Push pipeline for ${BUILDKITE_BRANCH:-?unknown branch?}"
pull_or_push_steps
wait_step
-trigger_secondary_step
+#trigger_secondary_step
exit 0
diff --git a/ci/buildkite-solana-private.sh b/ci/buildkite-solana-private.sh
index 7a2f19d45f..026ebdaf86 100644
--- a/ci/buildkite-solana-private.sh
+++ b/ci/buildkite-solana-private.sh
@@ -185,7 +185,7 @@ all_test_steps() {
queue: "sol-private"
EOF
else
- annotate --style info \
+ annotate --style info --context test-stable-bpf \
"Stable-BPF skipped as no relevant files were modified"
fi
@@ -203,16 +203,19 @@ EOF
^programs/ \
^sdk/ \
; then
- cat >> "$output_file" <<"EOF"
- - command: "ci/test-stable-perf.sh"
- name: "stable-perf"
- timeout_in_minutes: 35
- artifact_paths: "log-*.txt"
- agents:
- queue: "sol-private"
-EOF
+
+annotate --style warning --context test-stable-perf \
+ "test-stable-perf is currently disabled because it requires GPUs (LB)"
+# cat >> "$output_file" <<"EOF"
+# - command: "ci/test-stable-perf.sh"
+# name: "stable-perf"
+# timeout_in_minutes: 35
+# artifact_paths: "log-*.txt"
+# agents:
+# queue: "sol-private"
+#EOF
else
- annotate --style info \
+ annotate --style info --context test-stable-perf \
"Stable-perf skipped as no relevant files were modified"
fi
@@ -239,7 +242,7 @@ EOF
queue: "sol-private"
EOF
else
- annotate --style info \
+ annotate --style info --context test-downstream-projects \
"downstream-projects skipped as no relevant files were modified"
fi
@@ -249,9 +252,11 @@ EOF
^ci/test-stable.sh \
^sdk/ \
; then
- command_step wasm ". ci/rust-version.sh; ci/docker-run.sh \$\$rust_stable_docker_image ci/test-wasm.sh" 20
+ annotate --style warning --context test-wasm \
+ "test-wasm is currently disabled because it times out (LB)"
+# command_step wasm ". ci/rust-version.sh; ci/docker-run.sh \$\$rust_stable_docker_image ci/test-wasm.sh" 20
else
- annotate --style info \
+ annotate --style info --context test-wasm \
"wasm skipped as no relevant files were modified"
fi
diff --git a/ci/docker-rust/Dockerfile b/ci/docker-rust/Dockerfile
index 6805f85fcd..cd638e5c28 100644
--- a/ci/docker-rust/Dockerfile
+++ b/ci/docker-rust/Dockerfile
@@ -40,6 +40,7 @@ RUN set -x \
&& cargo install mdbook-linkcheck \
&& cargo install svgbob_cli \
&& cargo install wasm-pack \
+ && cargo install sccache \
&& rustc --version \
&& cargo --version \
&& curl -OL https://github.com/google/protobuf/releases/download/v$PROTOC_VERSION/$PROTOC_ZIP \
diff --git a/ci/rust-version.sh b/ci/rust-version.sh
index dc3570fa93..aec772f68f 100644
--- a/ci/rust-version.sh
+++ b/ci/rust-version.sh
@@ -42,6 +42,7 @@ export rust_nightly_docker_image=solanalabs/rust-nightly:"$nightly_version"
echo "$0: Missing toolchain? Installing...: $toolchain" >&2
rustup install "$toolchain"
cargo +"$toolchain" -V
+ rustup component add rustfmt --toolchain "$toolchain"
fi
}
diff --git a/ci/test-stable.sh b/ci/test-stable.sh
index e3a630599d..dd70804696 100755
--- a/ci/test-stable.sh
+++ b/ci/test-stable.sh
@@ -119,7 +119,7 @@ test-stable-bpf)
# latest mainbeta release version.
solana_program_count=$(grep -c 'solana-program v' cargo.log)
rm -f cargo.log
- if ((solana_program_count > 10)); then
+ if ((solana_program_count > 20)); then
echo "Regression of build redundancy ${solana_program_count}."
echo "Review dependency features that trigger redundant rebuilds of solana-program."
exit 1
diff --git a/client/src/http_sender.rs b/client/src/http_sender.rs
index 18caad62d6..c732208c1a 100644
--- a/client/src/http_sender.rs
+++ b/client/src/http_sender.rs
@@ -71,6 +71,110 @@ impl HttpSender {
stats: RwLock::new(RpcTransportStats::default()),
}
}
+
+ fn check_response(json: &serde_json::Value) -> Result<()> {
+ if json["error"].is_object() {
+ return match serde_json::from_value::(json["error"].clone()) {
+ Ok(rpc_error_object) => {
+ let data = match rpc_error_object.code {
+ rpc_custom_error::JSON_RPC_SERVER_ERROR_SEND_TRANSACTION_PREFLIGHT_FAILURE => {
+ match serde_json::from_value::(
+ json["error"]["data"].clone(),
+ ) {
+ Ok(data) => {
+ RpcResponseErrorData::SendTransactionPreflightFailure(data)
+ }
+ Err(err) => {
+ debug!(
+ "Failed to deserialize RpcSimulateTransactionResult: {:?}",
+ err
+ );
+ RpcResponseErrorData::Empty
+ }
+ }
+ }
+ rpc_custom_error::JSON_RPC_SERVER_ERROR_NODE_UNHEALTHY => {
+ match serde_json::from_value::(
+ json["error"]["data"].clone(),
+ ) {
+ Ok(rpc_custom_error::NodeUnhealthyErrorData { num_slots_behind }) => {
+ RpcResponseErrorData::NodeUnhealthy { num_slots_behind }
+ }
+ Err(_err) => RpcResponseErrorData::Empty,
+ }
+ }
+ _ => RpcResponseErrorData::Empty,
+ };
+
+ Err(RpcError::RpcResponseError {
+ request_id: json["id"].as_u64().unwrap(),
+ code: rpc_error_object.code,
+ message: rpc_error_object.message,
+ data,
+ }
+ .into())
+ }
+ Err(err) => Err(RpcError::RpcRequestError(format!(
+ "Failed to deserialize RPC error response: {} [{}]",
+ serde_json::to_string(&json["error"]).unwrap(),
+ err
+ ))
+ .into()),
+ };
+ }
+ Ok(())
+ }
+
+ async fn do_send_with_retry(
+ &self,
+ request: serde_json::Value,
+ ) -> reqwest::Result {
+ let mut stats_updater = StatsUpdater::new(&self.stats);
+ let mut too_many_requests_retries = 5;
+ loop {
+ let response = {
+ let client = self.client.clone();
+ let request = request.to_string();
+ client
+ .post(&self.url)
+ .header(CONTENT_TYPE, "application/json")
+ .body(request)
+ .send()
+ .await
+ }?;
+
+ if !response.status().is_success() {
+ if response.status() == StatusCode::TOO_MANY_REQUESTS
+ && too_many_requests_retries > 0
+ {
+ let mut duration = Duration::from_millis(500);
+ if let Some(retry_after) = response.headers().get(RETRY_AFTER) {
+ if let Ok(retry_after) = retry_after.to_str() {
+ if let Ok(retry_after) = retry_after.parse::() {
+ if retry_after < 120 {
+ duration = Duration::from_secs(retry_after);
+ }
+ }
+ }
+ }
+
+ too_many_requests_retries -= 1;
+ debug!(
+ "Too many requests: server responded with {:?}, {} retries left, pausing for {:?}",
+ response, too_many_requests_retries, duration
+ );
+
+ sleep(duration).await;
+ stats_updater.add_rate_limited_time(duration);
+
+ continue;
+ }
+ return Err(response.error_for_status().unwrap_err());
+ }
+
+ return response.json::().await;
+ }
+ }
}
#[derive(Deserialize, Debug)]
@@ -110,103 +214,37 @@ impl<'a> Drop for StatsUpdater<'a> {
#[async_trait]
impl RpcSender for HttpSender {
- fn get_transport_stats(&self) -> RpcTransportStats {
- self.stats.read().unwrap().clone()
- }
-
async fn send(
&self,
request: RpcRequest,
params: serde_json::Value,
) -> Result {
- let mut stats_updater = StatsUpdater::new(&self.stats);
-
let request_id = self.request_id.fetch_add(1, Ordering::Relaxed);
- let request_json = request.build_request_json(request_id, params).to_string();
+ let request = request.build_request_json(request_id, params);
+ let mut resp = self.do_send_with_retry(request).await?;
+ Self::check_response(&resp)?;
- let mut too_many_requests_retries = 5;
- loop {
- let response = {
- let client = self.client.clone();
- let request_json = request_json.clone();
- client
- .post(&self.url)
- .header(CONTENT_TYPE, "application/json")
- .body(request_json)
- .send()
- .await
- }?;
+ Ok(resp["result"].take())
+ }
- if !response.status().is_success() {
- if response.status() == StatusCode::TOO_MANY_REQUESTS
- && too_many_requests_retries > 0
- {
- let mut duration = Duration::from_millis(500);
- if let Some(retry_after) = response.headers().get(RETRY_AFTER) {
- if let Ok(retry_after) = retry_after.to_str() {
- if let Ok(retry_after) = retry_after.parse::() {
- if retry_after < 120 {
- duration = Duration::from_secs(retry_after);
- }
- }
- }
- }
+ async fn send_batch(
+ &self,
+ requests_and_params: Vec<(RpcRequest, serde_json::Value)>,
+ ) -> Result {
+ let mut batch_request = vec![];
+ for (request_id, req) in requests_and_params.into_iter().enumerate() {
+ batch_request.push(req.0.build_request_json(request_id as u64, req.1));
+ }
- too_many_requests_retries -= 1;
- debug!(
- "Too many requests: server responded with {:?}, {} retries left, pausing for {:?}",
- response, too_many_requests_retries, duration
- );
+ let resp = self
+ .do_send_with_retry(serde_json::Value::Array(batch_request))
+ .await?;
- sleep(duration).await;
- stats_updater.add_rate_limited_time(duration);
- continue;
- }
- return Err(response.error_for_status().unwrap_err().into());
- }
+ Ok(resp)
+ }
- let mut json = response.json::().await?;
- if json["error"].is_object() {
- return match serde_json::from_value::(json["error"].clone()) {
- Ok(rpc_error_object) => {
- let data = match rpc_error_object.code {
- rpc_custom_error::JSON_RPC_SERVER_ERROR_SEND_TRANSACTION_PREFLIGHT_FAILURE => {
- match serde_json::from_value::(json["error"]["data"].clone()) {
- Ok(data) => RpcResponseErrorData::SendTransactionPreflightFailure(data),
- Err(err) => {
- debug!("Failed to deserialize RpcSimulateTransactionResult: {:?}", err);
- RpcResponseErrorData::Empty
- }
- }
- },
- rpc_custom_error::JSON_RPC_SERVER_ERROR_NODE_UNHEALTHY => {
- match serde_json::from_value::(json["error"]["data"].clone()) {
- Ok(rpc_custom_error::NodeUnhealthyErrorData {num_slots_behind}) => RpcResponseErrorData::NodeUnhealthy {num_slots_behind},
- Err(_err) => {
- RpcResponseErrorData::Empty
- }
- }
- },
- _ => RpcResponseErrorData::Empty
- };
-
- Err(RpcError::RpcResponseError {
- code: rpc_error_object.code,
- message: rpc_error_object.message,
- data,
- }
- .into())
- }
- Err(err) => Err(RpcError::RpcRequestError(format!(
- "Failed to deserialize RPC error response: {} [{}]",
- serde_json::to_string(&json["error"]).unwrap(),
- err
- ))
- .into()),
- };
- }
- return Ok(json["result"].take());
- }
+ fn get_transport_stats(&self) -> RpcTransportStats {
+ self.stats.read().unwrap().clone()
}
fn url(&self) -> String {
diff --git a/client/src/mock_sender.rs b/client/src/mock_sender.rs
index 057dbed5c8..2a26c8c0b4 100644
--- a/client/src/mock_sender.rs
+++ b/client/src/mock_sender.rs
@@ -484,4 +484,11 @@ impl RpcSender for MockSender {
fn url(&self) -> String {
format!("MockSender: {}", self.url)
}
+
+ async fn send_batch(
+ &self,
+ _requests_and_params: Vec<(RpcRequest, serde_json::Value)>,
+ ) -> Result {
+ todo!()
+ }
}
diff --git a/client/src/nonblocking/rpc_client.rs b/client/src/nonblocking/rpc_client.rs
index e47908016f..014d6cf118 100644
--- a/client/src/nonblocking/rpc_client.rs
+++ b/client/src/nonblocking/rpc_client.rs
@@ -37,6 +37,7 @@ use {
},
solana_sdk::{
account::Account,
+ bundle::VersionedBundle,
clock::{Epoch, Slot, UnixTimestamp, DEFAULT_MS_PER_SLOT, MAX_HASH_AGE_IN_SECONDS},
commitment_config::{CommitmentConfig, CommitmentLevel},
epoch_info::EpochInfo,
@@ -45,7 +46,7 @@ use {
hash::Hash,
pubkey::Pubkey,
signature::Signature,
- transaction,
+ transaction::{self, VersionedTransaction},
},
solana_transaction_status::{
EncodedConfirmedBlock, EncodedConfirmedTransactionWithStatusMeta, TransactionStatus,
@@ -960,6 +961,7 @@ impl RpcClient {
code,
message,
data,
+ ..
}) = &err.kind
{
debug!("{} {}", code, message);
@@ -1406,6 +1408,113 @@ impl RpcClient {
.await
}
+ pub async fn batch_simulate_bundle(
+ &self,
+ bundles: &[VersionedBundle],
+ ) -> BatchRpcResult {
+ let configs = bundles
+ .iter()
+ .map(|b| RpcSimulateBundleConfig {
+ simulation_bank: Some(SimulationSlotConfig::Commitment(self.commitment())),
+ pre_execution_accounts_configs: vec![None; b.transactions.len()],
+ post_execution_accounts_configs: vec![None; b.transactions.len()],
+ ..RpcSimulateBundleConfig::default()
+ })
+ .collect::>();
+
+ self.batch_simulate_bundle_with_config(bundles.iter().zip(configs).collect())
+ .await
+ }
+
+ pub async fn batch_simulate_bundle_with_config(
+ &self,
+ bundles_and_configs: Vec<(&VersionedBundle, RpcSimulateBundleConfig)>,
+ ) -> BatchRpcResult {
+ let mut params = vec![];
+ for (bundle, config) in bundles_and_configs {
+ let transaction_encoding = if let Some(encoding) = config.transaction_encoding {
+ encoding
+ } else {
+ self.default_cluster_transaction_encoding().await?
+ };
+
+ let simulation_bank = config.simulation_bank.unwrap_or_default();
+
+ let config = RpcSimulateBundleConfig {
+ transaction_encoding: Some(transaction_encoding),
+ simulation_bank: Some(simulation_bank),
+ ..config
+ };
+
+ let encoded_transactions = bundle
+ .transactions
+ .iter()
+ .map(|tx| serialize_and_encode::(tx, transaction_encoding))
+ .collect::, ClientError>>()?;
+ let rpc_bundle_request = RpcBundleRequest {
+ encoded_transactions,
+ };
+
+ params.push(json!([rpc_bundle_request, config]));
+ }
+
+ let requests_and_params = vec![RpcRequest::SimulateBundle; params.len()]
+ .into_iter()
+ .zip(params)
+ .collect();
+ self.send_batch(requests_and_params).await
+ }
+
+ pub async fn simulate_bundle(
+ &self,
+ bundle: &VersionedBundle,
+ ) -> RpcResult {
+ self.simulate_bundle_with_config(
+ bundle,
+ RpcSimulateBundleConfig {
+ simulation_bank: Some(SimulationSlotConfig::Commitment(self.commitment())),
+ pre_execution_accounts_configs: vec![None; bundle.transactions.len()],
+ post_execution_accounts_configs: vec![None; bundle.transactions.len()],
+ ..RpcSimulateBundleConfig::default()
+ },
+ )
+ .await
+ }
+
+ pub async fn simulate_bundle_with_config(
+ &self,
+ bundle: &VersionedBundle,
+ config: RpcSimulateBundleConfig,
+ ) -> RpcResult {
+ let transaction_encoding = if let Some(enc) = config.transaction_encoding {
+ enc
+ } else {
+ self.default_cluster_transaction_encoding().await?
+ };
+ let simulation_bank = Some(config.simulation_bank.unwrap_or_default());
+
+ let encoded_transactions = bundle
+ .transactions
+ .iter()
+ .map(|tx| serialize_and_encode::(tx, transaction_encoding))
+ .collect::>>()?;
+ let rpc_bundle_request = RpcBundleRequest {
+ encoded_transactions,
+ };
+
+ let config = RpcSimulateBundleConfig {
+ transaction_encoding: Some(transaction_encoding),
+ simulation_bank,
+ ..config
+ };
+
+ self.send(
+ RpcRequest::SimulateBundle,
+ json!([rpc_bundle_request, config]),
+ )
+ .await
+ }
+
/// Returns the highest slot information that the node has snapshots for.
///
/// This will find the highest full snapshot slot, and the highest incremental snapshot slot
@@ -5455,6 +5564,22 @@ impl RpcClient {
.map_err(|err| ClientError::new_with_request(err.into(), request))
}
+ pub async fn send_batch(
+ &self,
+ requests_and_params: Vec<(RpcRequest, Value)>,
+ ) -> ClientResult
+ where
+ T: serde::de::DeserializeOwned,
+ {
+ let response = self.sender.send_batch(requests_and_params).await?;
+ debug!("response: {:?}", response);
+
+ serde_json::from_value(response).map_err(|err| ClientError {
+ request: None,
+ kind: err.into(),
+ })
+ }
+
pub fn get_transport_stats(&self) -> RpcTransportStats {
self.sender.get_transport_stats()
}
diff --git a/client/src/rpc_client.rs b/client/src/rpc_client.rs
index bac070ce6f..d2efc9ad1e 100644
--- a/client/src/rpc_client.rs
+++ b/client/src/rpc_client.rs
@@ -28,6 +28,7 @@ use {
},
solana_sdk::{
account::Account,
+ bundle::VersionedBundle,
clock::{Epoch, Slot, UnixTimestamp},
commitment_config::CommitmentConfig,
epoch_info::EpochInfo,
@@ -1151,6 +1152,35 @@ impl RpcClient {
)
}
+ pub fn batch_simulate_bundle(
+ &self,
+ bundles: &[VersionedBundle],
+ ) -> BatchRpcResult {
+ self.invoke(self.rpc_client.batch_simulate_bundle(bundles))
+ }
+
+ pub fn batch_simulate_bundle_with_config(
+ &self,
+ bundles_and_configs: Vec<(&VersionedBundle, RpcSimulateBundleConfig)>,
+ ) -> BatchRpcResult {
+ self.invoke(
+ self.rpc_client
+ .batch_simulate_bundle_with_config(bundles_and_configs),
+ )
+ }
+
+ pub fn simulate_bundle(&self, bundle: &VersionedBundle) -> RpcResult {
+ self.invoke(self.rpc_client.simulate_bundle(bundle))
+ }
+
+ pub fn simulate_bundle_with_config(
+ &self,
+ bundle: &VersionedBundle,
+ config: RpcSimulateBundleConfig,
+ ) -> RpcResult {
+ self.invoke(self.rpc_client.simulate_bundle_with_config(bundle, config))
+ }
+
/// Returns the highest slot information that the node has snapshots for.
///
/// This will find the highest full snapshot slot, and the highest incremental snapshot slot
diff --git a/client/src/rpc_config.rs b/client/src/rpc_config.rs
index d5bc986a21..8877a789cb 100644
--- a/client/src/rpc_config.rs
+++ b/client/src/rpc_config.rs
@@ -46,7 +46,57 @@ pub struct RpcSimulateTransactionConfig {
pub min_context_slot: Option,
}
-#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
+#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, PartialEq)]
+#[serde(rename_all = "camelCase")]
+pub enum SimulationSlotConfig {
+ /// Simulate on top of bank with the provided commitment.
+ Commitment(CommitmentConfig),
+
+ /// Simulate on the provided slot's bank.
+ Slot(Slot),
+
+ /// Simulates on top of the RPC's highest slot's bank i.e. the working bank.
+ Tip,
+}
+
+impl Default for SimulationSlotConfig {
+ fn default() -> Self {
+ Self::Commitment(CommitmentConfig {
+ commitment: CommitmentLevel::Confirmed,
+ })
+ }
+}
+
+#[derive(Debug, PartialEq, Default, Eq, Clone, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct RpcBundleRequest {
+ pub encoded_transactions: Vec,
+}
+
+#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct RpcSimulateBundleConfig {
+ /// Gives the state of accounts pre/post transaction execution.
+ /// The length of each of these must be equal to the number transactions.
+ pub pre_execution_accounts_configs: Vec