refactor: implement rpc authentication

closes #8

neptune-core RPC methods now require an authentication token.

This implements auth support in neptune-explorer.
This commit is contained in:
danda 2025-01-22 21:00:11 -08:00
parent af5496ed11
commit 8a79c578c2
13 changed files with 269 additions and 221 deletions

298
Cargo.lock generated
View File

@ -207,11 +207,13 @@ dependencies = [
[[package]]
name = "attribute-derive"
version = "0.6.1"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c124f12ade4e670107b132722d0ad1a5c9790bcbc1b265336369ea05626b4498"
checksum = "0053e96dd3bec5b4879c23a138d6ef26f2cb936c9cdc96274ac2b9ed44b5bb54"
dependencies = [
"attribute-derive-macro",
"derive-where",
"manyhow",
"proc-macro2",
"quote",
"syn 2.0.89",
@ -219,13 +221,13 @@ dependencies = [
[[package]]
name = "attribute-derive-macro"
version = "0.6.1"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b217a07446e0fb086f83401a98297e2d81492122f5874db5391bd270a185f88"
checksum = "463b53ad0fd5b460af4b1915fe045ff4d946d025fb6c4dc3337752eaa980f71b"
dependencies = [
"collection_literals",
"interpolator",
"proc-macro-error",
"manyhow",
"proc-macro-utils",
"proc-macro2",
"quote",
@ -404,21 +406,6 @@ dependencies = [
"serde",
]
[[package]]
name = "bit-set"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1"
dependencies = [
"bit-vec",
]
[[package]]
name = "bit-vec"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
[[package]]
name = "bitflags"
version = "1.3.2"
@ -630,6 +617,28 @@ dependencies = [
"cc",
]
[[package]]
name = "codspeed"
version = "2.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "450a0e9df9df1c154156f4344f99d8f6f6e69d0fc4de96ef6e2e68b2ec3bce97"
dependencies = [
"colored",
"libc",
"serde_json",
]
[[package]]
name = "codspeed-criterion-compat"
version = "2.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8eb1a6cb9c20e177fde58cdef97c1c7c9264eb1424fe45c4fccedc2fb078a569"
dependencies = [
"codspeed",
"colored",
"criterion",
]
[[package]]
name = "collection_literals"
version = "1.0.1"
@ -644,12 +653,12 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "colored"
version = "2.1.0"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8"
checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c"
dependencies = [
"lazy_static",
"windows-sys 0.48.0",
"windows-sys 0.52.0",
]
[[package]]
@ -1259,25 +1268,25 @@ dependencies = [
]
[[package]]
name = "get-size"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47b61e2dab7eedce93a83ab3468b919873ff16bac5a3e704011ff836d22b2120"
dependencies = [
"get-size-derive",
]
[[package]]
name = "get-size-derive"
name = "get-size-derive2"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13a1bcfb855c1f340d5913ab542e36f25a1c56f57de79022928297632435dec2"
checksum = "f05a48922b5f3de09a9e9de288039466a6c4e5f332b8532ba1e2665b05bfdde0"
dependencies = [
"attribute-derive",
"quote",
"syn 2.0.89",
]
[[package]]
name = "get-size2"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3aa3d1f2527cf956b5637a531e21eb1ef9c825c70cd6f8765fd00b7457eef699"
dependencies = [
"get-size-derive2",
]
[[package]]
name = "getrandom"
version = "0.2.14"
@ -1317,7 +1326,7 @@ dependencies = [
"futures-sink",
"futures-util",
"http 0.2.12",
"indexmap 2.6.0",
"indexmap 2.7.1",
"slab",
"tokio",
"tokio-util",
@ -1622,9 +1631,9 @@ dependencies = [
[[package]]
name = "indexmap"
version = "2.6.0"
version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652"
dependencies = [
"equivalent",
"hashbrown 0.15.1",
@ -1713,6 +1722,15 @@ dependencies = [
"either",
]
[[package]]
name = "itertools"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.11"
@ -1836,6 +1854,29 @@ dependencies = [
"hashbrown 0.15.1",
]
[[package]]
name = "manyhow"
version = "0.11.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b33efb3ca6d3b07393750d4030418d594ab1139cee518f0dc88db70fec873587"
dependencies = [
"manyhow-macros",
"proc-macro2",
"quote",
"syn 2.0.89",
]
[[package]]
name = "manyhow-macros"
version = "0.11.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46fce34d199b78b6e6073abf984c9cf5fd3e9330145a93ee0738a7443e371495"
dependencies = [
"proc-macro-utils",
"proc-macro2",
"quote",
]
[[package]]
name = "matchers"
version = "0.1.0"
@ -1969,12 +2010,11 @@ dependencies = [
[[package]]
name = "neptune-cash"
version = "0.0.10"
source = "git+https://github.com/Neptune-Crypto/neptune-core.git?rev=9602321148095f9991808780b406c1789f9a3a4f#9602321148095f9991808780b406c1789f9a3a4f"
source = "git+https://github.com/Neptune-Crypto/neptune-core.git?rev=89f5a1c2bb5f670071b71f2fef237c820e901f84#89f5a1c2bb5f670071b71f2fef237c820e901f84"
dependencies = [
"aead",
"aes-gcm",
"anyhow",
"arbitrary",
"async-stream",
"async-trait",
"bech32",
@ -1989,7 +2029,7 @@ dependencies = [
"directories",
"field_count",
"futures",
"get-size",
"get-size2",
"itertools 0.11.0",
"leveldb-sys",
"memmap2",
@ -1997,11 +2037,10 @@ dependencies = [
"num-rational",
"num-traits",
"priority-queue",
"proptest",
"proptest-arbitrary-interop",
"rand",
"rand_distr",
"ratatui",
"rayon",
"readonly",
"regex",
"rs-leveldb",
@ -2041,6 +2080,7 @@ dependencies = [
"clap",
"derive_more",
"html-escaper",
"indexmap 2.7.1",
"lettre",
"neptune-cash",
"readonly",
@ -2534,35 +2574,11 @@ dependencies = [
"indexmap 1.9.3",
]
[[package]]
name = "proc-macro-error"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
"proc-macro-error-attr",
"proc-macro2",
"quote",
"syn 1.0.109",
"version_check",
]
[[package]]
name = "proc-macro-error-attr"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
"proc-macro2",
"quote",
"version_check",
]
[[package]]
name = "proc-macro-utils"
version = "0.8.0"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f59e109e2f795a5070e69578c4dc101068139f74616778025ae1011d4cd41a8"
checksum = "eeaf08a13de400bc215877b5bdc088f241b12eb42f0a548d3390dc1c56bb7071"
dependencies = [
"proc-macro2",
"quote",
@ -2578,36 +2594,6 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "proptest"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d"
dependencies = [
"bit-set",
"bit-vec",
"bitflags 2.5.0",
"lazy_static",
"num-traits",
"rand",
"rand_chacha",
"rand_xorshift",
"regex-syntax 0.8.5",
"rusty-fork",
"tempfile",
"unarray",
]
[[package]]
name = "proptest-arbitrary-interop"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1981e49bd2432249da8b0e11e5557099a8e74690d6b94e721f7dc0bb7f3555f"
dependencies = [
"arbitrary",
"proptest",
]
[[package]]
name = "prost"
version = "0.12.4"
@ -2649,12 +2635,6 @@ dependencies = [
"cc",
]
[[package]]
name = "quick-error"
version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
[[package]]
name = "quote"
version = "1.0.36"
@ -2666,22 +2646,21 @@ dependencies = [
[[package]]
name = "quote-use"
version = "0.7.2"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7b5abe3fe82fdeeb93f44d66a7b444dedf2e4827defb0a8e69c437b2de2ef94"
checksum = "9619db1197b497a36178cfc736dc96b271fe918875fbf1344c436a7e93d0321e"
dependencies = [
"quote",
"quote-use-macros",
"syn 2.0.89",
]
[[package]]
name = "quote-use-macros"
version = "0.7.2"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97ea44c7e20f16017a76a245bb42188517e13d16dcb1aa18044bc406cdc3f4af"
checksum = "82ebfb7faafadc06a7ab141a6f67bcfb24cb8beb158c6fe933f2f035afa99f35"
dependencies = [
"derive-where",
"proc-macro-utils",
"proc-macro2",
"quote",
"syn 2.0.89",
@ -2733,15 +2712,6 @@ dependencies = [
"rand",
]
[[package]]
name = "rand_xorshift"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f"
dependencies = [
"rand_core",
]
[[package]]
name = "ratatui"
version = "0.29.0"
@ -2905,18 +2875,6 @@ version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47"
[[package]]
name = "rusty-fork"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f"
dependencies = [
"fnv",
"quick-error",
"tempfile",
"wait-timeout",
]
[[package]]
name = "ryu"
version = "1.0.17"
@ -3007,11 +2965,12 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.115"
version = "1.0.137"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd"
checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b"
dependencies = [
"itoa",
"memchr",
"ryu",
"serde",
]
@ -3282,9 +3241,9 @@ dependencies = [
[[package]]
name = "tasm-lib"
version = "0.43.0"
version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e2086093477a23c66dc1cfcbb3b3cd6eb9cbc96ab0b6d0b9f796ea14942760e"
checksum = "06a5540444a504eb4c1484a612033440be89470dc6ea6abcd41d4ec21b9fc71d"
dependencies = [
"anyhow",
"arbitrary",
@ -3304,9 +3263,9 @@ dependencies = [
[[package]]
name = "tasm-object-derive"
version = "0.43.0"
version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "018472cead7ee1ecfdf8114ba9021f857cdf511977e9a9e591ea796bfe7e5f12"
checksum = "66a681206ecb819215a9059d1993775ff14749aa5d2538037c86569b8a10ae40"
dependencies = [
"proc-macro2",
"quote",
@ -3759,12 +3718,12 @@ dependencies = [
[[package]]
name = "triton-air"
version = "0.43.0"
version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b8fe8a3218c33c6355de52ceabdcf30d328598cc750f5d52518d36aadb9cadf"
checksum = "5f8bcf2ed66f6baf5706c807c487221ebb54d73544056af2a26d5d4e88158211"
dependencies = [
"arbitrary",
"itertools 0.13.0",
"itertools 0.14.0",
"strum",
"triton-constraint-circuit",
"triton-isa",
@ -3773,11 +3732,11 @@ dependencies = [
[[package]]
name = "triton-constraint-builder"
version = "0.43.0"
version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e4f55397448ef663636c44eda9079db6aa09b1cff029dad271c8a897def6fcd"
checksum = "8b04a9802940bfa074b7ee58c0d21d249e066c39ac87eb67d1e59c2d7a93f500"
dependencies = [
"itertools 0.13.0",
"itertools 0.14.0",
"prettyplease",
"proc-macro2",
"quote",
@ -3791,12 +3750,12 @@ dependencies = [
[[package]]
name = "triton-constraint-circuit"
version = "0.43.0"
version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3420bac9a3188c6f53dfdd8f07811eea7dd2a42d3a615b1a91e78fb7a631b8a"
checksum = "6108efaf01ab461c27ab7c6a94601186a091a234746c6247c1856c47c43b0487"
dependencies = [
"arbitrary",
"itertools 0.13.0",
"itertools 0.14.0",
"ndarray",
"num-traits",
"proc-macro2",
@ -3806,13 +3765,13 @@ dependencies = [
[[package]]
name = "triton-isa"
version = "0.43.0"
version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd6c3f1a58e165309b3228e6f1e222aed443d4a345c07bfac09066997ca531b"
checksum = "20143568d1d6e742a2daf33c14fe0ef5002093835129a6f15203c1c6cad24eca"
dependencies = [
"arbitrary",
"get-size",
"itertools 0.13.0",
"get-size2",
"itertools 0.14.0",
"lazy_static",
"nom",
"num-traits",
@ -3824,16 +3783,16 @@ dependencies = [
[[package]]
name = "triton-vm"
version = "0.43.0"
version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05e71ae69a3db5d90022449f4db16ee44f4c16567dfea008474365d6963682dd"
checksum = "bfa8d39440ddcbe422bb0f6ad2227c8ba342813a550838337e583191c90ef083"
dependencies = [
"arbitrary",
"codspeed-criterion-compat",
"colored",
"criterion",
"get-size",
"indexmap 2.6.0",
"itertools 0.13.0",
"get-size2",
"indexmap 2.7.1",
"itertools 0.14.0",
"lazy_static",
"ndarray",
"num-traits",
@ -3863,16 +3822,16 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
[[package]]
name = "twenty-first"
version = "0.43.0"
version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7df8f51d2792092a8ad01824714872c598216e8b42280da672c913160f39c051"
checksum = "cd264235763e83dceee6b6c54e2a08989f30e89ccb70c4a3b673a15ce6100907"
dependencies = [
"arbitrary",
"bfieldcodec_derive",
"get-size",
"hashbrown 0.14.3",
"get-size2",
"hashbrown 0.15.1",
"hex",
"itertools 0.13.0",
"itertools 0.14.0",
"lazy_static",
"num-bigint",
"num-traits",
@ -3885,7 +3844,7 @@ dependencies = [
"serde_derive",
"serde_json",
"sha3",
"thiserror 1.0.69",
"thiserror 2.0.3",
]
[[package]]
@ -3894,12 +3853,6 @@ version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]]
name = "unarray"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94"
[[package]]
name = "unicase"
version = "2.7.0"
@ -4010,15 +3963,6 @@ version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "wait-timeout"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
dependencies = [
"libc",
]
[[package]]
name = "walkdir"
version = "2.5.0"

View File

@ -10,11 +10,11 @@ axum = { version = "0.7.9", features = ["macros"] }
serde = { version = "1.0.197", features = ["derive"] }
serde_json = "1.0.115"
tokio = { version = "1.37.0", features = ["full", "tracing"] }
tracing = "0.1.40"
tracing-subscriber = "0.3.18"
tracing = "0.1"
tracing-subscriber = "0.3"
# 9602321148095f9991808780b406c1789f9a3a4f = betanet
neptune-cash = {git = "https://github.com/Neptune-Crypto/neptune-core.git", rev = "9602321148095f9991808780b406c1789f9a3a4f"}
# 89f5a1c2bb5f670071b71f2fef237c820e901f84 = 2025-01-22, almost to betanet-v2
neptune-cash = {git = "https://github.com/Neptune-Crypto/neptune-core.git", rev = "89f5a1c2bb5f670071b71f2fef237c820e901f84"}
tarpc = { version = "^0.34", features = [
"tokio1",
"serde-transport",
@ -36,6 +36,9 @@ anyhow = "1.0.86"
arc-swap = "1.7.1"
derive_more = { version = "1.0.0", features = ["display"] }
# not a direct dep. workaround for weird "could not resolve" cargo error
indexmap = "2.7.0"
[patch.crates-io]
# 694f27daf78aade0ed0dc07e3babaab036cd5572 is tip of branch: master as of 2024-04-30
#tasm-lib = { git = "https://github.com/TritonVM/tasm-lib.git", rev = "694f27daf78aade0ed0dc07e3babaab036cd5572" }

View File

@ -1,5 +1,6 @@
use crate::html::component::header::HeaderHtml;
use crate::html::page::not_found::not_found_html_response;
use crate::http_util::rpc_method_err;
use crate::model::app_state::AppState;
use crate::model::block_selector_extended::BlockSelectorExtended;
use axum::extract::rejection::PathRejection;
@ -31,9 +32,10 @@ pub async fn block_page(
let block_info = match state
.rpc_client
.block_info(context::current(), block_selector.into())
.block_info(context::current(), state.token(), block_selector.into())
.await
.map_err(|e| not_found_html_response(state, Some(e.to_string())))?
.map_err(rpc_method_err)?
{
Some(info) => Ok(info),
None => Err(not_found_html_response(

View File

@ -1,4 +1,5 @@
use crate::html::page::not_found::not_found_html_response;
use crate::http_util::rpc_method_err;
use crate::model::app_state::AppState;
use crate::model::app_state::AppStateInner;
use axum::extract::State;
@ -22,9 +23,10 @@ pub async fn root(State(state_rw): State<Arc<AppState>>) -> Result<Html<String>,
let tip_height = state
.rpc_client
.block_height(context::current())
.block_height(context::current(), state.token())
.await
.map_err(|e| not_found_html_response(state, Some(e.to_string())))?;
.map_err(|e| not_found_html_response(state, Some(e.to_string())))?
.map_err(rpc_method_err)?;
let root_page = RootHtmlPage { tip_height, state };
Ok(Html(root_page.to_string()))

View File

@ -1,5 +1,6 @@
use crate::html::component::header::HeaderHtml;
use crate::html::page::not_found::not_found_html_response;
use crate::http_util::rpc_method_err;
use crate::model::app_state::AppState;
use axum::extract::rejection::PathRejection;
use axum::extract::Path;
@ -8,7 +9,7 @@ use axum::response::Html;
use axum::response::Response;
use html_escaper::Escape;
use html_escaper::Trusted;
use neptune_cash::prelude::tasm_lib::Digest;
use neptune_cash::prelude::tasm_lib::prelude::Digest;
use std::sync::Arc;
use tarpc::context;
@ -32,9 +33,10 @@ pub async fn utxo_page(
let digest = match state
.rpc_client
.utxo_digest(context::current(), index)
.utxo_digest(context::current(), state.token(), index)
.await
.map_err(|e| not_found_html_response(state, Some(e.to_string())))?
.map_err(rpc_method_err)?
{
Some(digest) => digest,
None => {

View File

@ -2,7 +2,8 @@ use axum::http::StatusCode;
use axum::response::Html;
use axum::response::IntoResponse;
use axum::response::Response;
use tarpc::client::RpcError;
use neptune_cash::rpc_server::error::RpcError;
use tarpc::client::RpcError as TarpcError;
// note: http StatusCodes are defined at:
// https://docs.rs/http/1.1.0/http/status/struct.StatusCode.html
@ -19,6 +20,11 @@ pub fn not_found_html_handler(html: Html<String>) -> (StatusCode, Html<String>)
(StatusCode::NOT_FOUND, html)
}
pub fn rpc_err(e: RpcError) -> Response {
pub fn rpc_err(e: TarpcError) -> Response {
(StatusCode::INTERNAL_SERVER_ERROR, format!("{:?}", e)).into_response()
}
pub fn rpc_method_err(e: RpcError) -> Response {
// todo: handle auth variant.
(StatusCode::BAD_REQUEST, format!("{:?}", e)).into_response()
}

View File

@ -6,16 +6,22 @@ use clap::Parser;
use neptune_cash::config_models::network::Network;
use neptune_cash::models::blockchain::block::block_selector::BlockSelector;
use neptune_cash::prelude::twenty_first::math::digest::Digest;
use neptune_cash::rpc_server::RPCClient;
use neptune_cash::rpc_auth;
use std::sync::Arc;
pub struct AppStateInner {
pub network: Network,
pub config: Config,
pub rpc_client: RPCClient,
pub rpc_client: neptune_rpc::AuthenticatedClient,
pub genesis_digest: Digest,
}
impl AppStateInner {
pub fn token(&self) -> rpc_auth::Token {
self.rpc_client.token
}
}
#[derive(Clone)]
pub struct AppState(Arc<ArcSwap<AppStateInner>>);
@ -27,9 +33,14 @@ impl std::ops::Deref for AppState {
}
}
impl From<(Network, Config, RPCClient, Digest)> for AppState {
impl From<(Network, Config, neptune_rpc::AuthenticatedClient, Digest)> for AppState {
fn from(
(network, config, rpc_client, genesis_digest): (Network, Config, RPCClient, Digest),
(network, config, rpc_client, genesis_digest): (
Network,
Config,
neptune_rpc::AuthenticatedClient,
Digest,
),
) -> Self {
Self(Arc::new(ArcSwap::from_pointee(AppStateInner {
network,
@ -42,21 +53,22 @@ impl From<(Network, Config, RPCClient, Digest)> for AppState {
impl AppState {
pub async fn init() -> Result<Self, anyhow::Error> {
let rpc_client = neptune_rpc::gen_rpc_client()
let rpc_client = neptune_rpc::gen_authenticated_rpc_client()
.await
.with_context(|| "Failed to create RPC client")?;
let network = rpc_client
.network(tarpc::context::current())
.await
.with_context(|| "Failed calling neptune-core api: network")?;
let genesis_digest = rpc_client
.block_digest(tarpc::context::current(), BlockSelector::Genesis)
.block_digest(
tarpc::context::current(),
rpc_client.token,
BlockSelector::Genesis,
)
.await
.with_context(|| "Failed calling neptune-core api: block_digest")?
.with_context(|| "Failed calling neptune-core api method: block_digest")?
.with_context(|| "neptune-core failed to provide a genesis block")?;
Ok(Self::from((
network,
rpc_client.network,
Config::parse(),
rpc_client,
genesis_digest,
@ -74,12 +86,12 @@ impl AppState {
///
/// Note that this method takes &self, so interior
/// mutability occurs.
pub fn set_rpc_client(&self, rpc_client: RPCClient) {
pub fn set_rpc_client(&self, rpc_client: neptune_rpc::AuthenticatedClient) {
let inner = self.0.load();
let new_inner = AppStateInner {
network: rpc_client.network,
rpc_client,
network: inner.network,
config: inner.config.clone(),
genesis_digest: inner.genesis_digest,
};

View File

@ -1,7 +1,7 @@
use neptune_cash::models::blockchain::block::block_height::BlockHeight;
use neptune_cash::models::blockchain::block::block_selector::BlockSelector;
use neptune_cash::models::blockchain::block::block_selector::BlockSelectorParseError;
use neptune_cash::prelude::tasm_lib::Digest;
use neptune_cash::prelude::tasm_lib::prelude::Digest;
use serde::{Deserialize, Serialize};
use std::str::FromStr;

View File

@ -6,7 +6,11 @@ use chrono::DateTime;
use chrono::TimeDelta;
use chrono::Utc;
use clap::Parser;
use neptune_cash::config_models::data_directory::DataDirectory;
use neptune_cash::config_models::network::Network;
use neptune_cash::models::blockchain::block::block_height::BlockHeight;
use neptune_cash::rpc_auth;
use neptune_cash::rpc_server::error::RpcError;
use neptune_cash::rpc_server::RPCClient;
use std::net::Ipv4Addr;
use std::net::SocketAddr;
@ -15,6 +19,38 @@ use tarpc::context;
use tarpc::tokio_serde::formats::Json as RpcJson;
use tracing::{debug, info, warn};
pub struct AuthenticatedClient {
pub client: RPCClient,
pub token: rpc_auth::Token,
pub network: Network,
}
impl std::ops::Deref for AuthenticatedClient {
type Target = RPCClient;
fn deref(&self) -> &Self::Target {
&self.client
}
}
/// generates RPCClient, for querying neptune-core RPC server.
pub async fn gen_authenticated_rpc_client() -> Result<AuthenticatedClient, anyhow::Error> {
let client = gen_rpc_client().await?;
let rpc_auth::CookieHint {
data_directory,
network,
} = get_cookie_hint(&client, &None).await?;
let token: rpc_auth::Token = rpc_auth::Cookie::try_load(&data_directory).await?.into();
Ok(AuthenticatedClient {
client,
token,
network,
})
}
/// generates RPCClient, for querying neptune-core RPC server.
pub async fn gen_rpc_client() -> Result<RPCClient, anyhow::Error> {
// Create connection to neptune-core RPC server
@ -31,6 +67,41 @@ pub async fn gen_rpc_client() -> Result<RPCClient, anyhow::Error> {
Ok(RPCClient::new(client::Config::default(), transport).spawn())
}
// returns result with a CookieHint{ data_directory, network }.
//
// We use the data-dir provided by user if present.
//
// Otherwise we call cookie_hint() RPC to obtain data-dir.
// But the API might be disabled, which we detect and fallback to the default data-dir.
async fn get_cookie_hint(
client: &RPCClient,
data_dir: &Option<std::path::PathBuf>,
) -> anyhow::Result<rpc_auth::CookieHint> {
async fn fallback(
client: &RPCClient,
data_dir: &Option<std::path::PathBuf>,
) -> anyhow::Result<rpc_auth::CookieHint> {
let network = client.network(context::current()).await??;
let data_directory = DataDirectory::get(data_dir.to_owned(), network)?;
Ok(rpc_auth::CookieHint {
data_directory,
network,
})
}
if data_dir.is_some() {
return fallback(client, data_dir).await;
}
let result = client.cookie_hint(context::current()).await?;
match result {
Ok(hint) => Ok(hint),
Err(RpcError::CookieHintDisabled) => fallback(client, data_dir).await,
Err(e) => Err(e.into()),
}
}
/// a tokio task that periodically pings neptune-core rpc server to ensure the
/// connection is still alive and/or attempts to re-establish connection.
///
@ -93,7 +164,7 @@ pub async fn watchdog(app_state: AppState) {
}
if !now_connected {
if let Ok(c) = gen_rpc_client().await {
if let Ok(c) = gen_authenticated_rpc_client().await {
app_state.set_rpc_client(c);
}
}
@ -156,13 +227,14 @@ pub async fn blockchain_watchdog(app_state: AppState) {
debug!("neptune-core blockchain watchdog started");
loop {
let result = app_state
.load()
.rpc_client
.block_height(context::current())
.await;
let result = {
let s = app_state.load();
s.rpc_client
.block_height(context::current(), s.token())
.await
};
if let Ok(height) = result {
if let Ok(Ok(height)) = result {
// send admin alert if there is a state change.
let subject = match last_blockchain_state {
BlockchainState::Normal if height < last_height => {
@ -215,8 +287,7 @@ pub async fn blockchain_watchdog(app_state: AppState) {
// update state.
last_height = height;
since = chrono::offset::Utc::now();
tokio::time::sleep(tokio::time::Duration::from_secs(watchdog_secs)).await;
}
tokio::time::sleep(tokio::time::Duration::from_secs(watchdog_secs)).await;
}
}

View File

@ -1,5 +1,6 @@
use crate::http_util::not_found_err;
use crate::http_util::rpc_err;
use crate::http_util::rpc_method_err;
use crate::model::app_state::AppState;
use crate::model::block_selector_extended::BlockSelectorExtended;
use axum::extract::Path;
@ -15,12 +16,13 @@ pub async fn block_digest(
Path(selector): Path<BlockSelectorExtended>,
State(state): State<Arc<AppState>>,
) -> Result<Json<Digest>, impl IntoResponse> {
match state
.load()
let s = state.load();
match s
.rpc_client
.block_digest(context::current(), selector.into())
.block_digest(context::current(), s.token(), selector.into())
.await
.map_err(rpc_err)?
.map_err(rpc_method_err)?
{
Some(digest) => Ok(Json(digest)),
None => Err(not_found_err()),

View File

@ -1,5 +1,6 @@
use crate::http_util::not_found_err;
use crate::http_util::rpc_err;
use crate::http_util::rpc_method_err;
use crate::model::app_state::AppState;
use crate::model::block_selector_extended::BlockSelectorExtended;
use axum::extract::Path;
@ -15,12 +16,13 @@ pub async fn block_info(
Path(selector): Path<BlockSelectorExtended>,
State(state): State<Arc<AppState>>,
) -> Result<Json<BlockInfo>, Response> {
let block_info = state
.load()
let s = state.load();
let block_info = s
.rpc_client
.block_info(context::current(), selector.into())
.block_info(context::current(), s.token(), selector.into())
.await
.map_err(rpc_err)?
.map_err(rpc_method_err)?
.ok_or_else(not_found_err)?;
Ok(Json(block_info))

View File

@ -6,6 +6,7 @@ use neptune_cash::prelude::twenty_first::math::digest::Digest;
use std::sync::Arc;
use tarpc::context;
use crate::http_util::rpc_method_err;
use crate::{
http_util::{not_found_err, rpc_err},
model::app_state::AppState,
@ -16,12 +17,13 @@ pub async fn utxo_digest(
Path(index): Path<u64>,
State(state): State<Arc<AppState>>,
) -> Result<Json<Digest>, impl IntoResponse> {
match state
.load()
let s = state.load();
match s
.rpc_client
.utxo_digest(context::current(), index)
.utxo_digest(context::current(), s.token(), index)
.await
.map_err(rpc_err)?
.map_err(rpc_method_err)?
{
Some(digest) => Ok(Json(digest)),
None => Err(not_found_err()),

View File

@ -118,7 +118,7 @@
%% if self.block_info.is_genesis {
| Previous Block
%% } else {
| <a href='/block/height/{{self.block_info.height.previous()}}'>Previous Block</a>
| <a href='/block/height/{{self.block_info.height.previous().unwrap()}}'>Previous Block</a>
%% }
%% if self.block_info.is_tip {