feature(rpc): implement getblock api call (#3707)
* feature(rpc): start adding a `getblock` method * fix(rpc): replace oneshot * fix(rpc): replace a panic with error * fix(rpc): fix test * feature(rpc): add hex to response * refactor(rpc): use generic instead of alias * docs(rpc): improve docs for getblock method * test(rpc): add a test for getblock method * deps(rpc): remove non needed tower features Co-authored-by: teor <teor@riseup.net> * docs(rpc): add a note to getblock doc * refactor(rpc): replace alias * fix(rpc): use `zcash_serialize_to_vec()` instead of logging format * tests(rpc): add network argument to `populated_state()` * refactor(rpc): use an error for state service readiness * fix(rpc): add parameter * fix(rpc): clippy * nit(rpc): remove new line from imports * fix(rpc): remove commented code * fix(rpc): simplify error Co-authored-by: Janito Vaqueiro Ferreira Filho <janito.vff@gmail.com> * Use a `SerializedBlock` type to help serializing blocks (#3725) * Create a `SerializedBlock` helper type Create a type that can be used as a byte slice, but is guaranteed to represent a valid block. * Use `into_iter` instead of `iter` There's no need to borrow the elements, they can be moved out directly. This will be necessary because `&Arc<T>` doesn't implement `Borrow<T>`, so a `SerializedBlock` can't be built directly from an `&Arc<Block>`. * Use `SerializedBlock` in `GetBlock` Make the type stricter to avoid storing possibly invalid values. The bytes are still serialized as a hexadecimal string, through the usage of `hex`. The `serde::Deserialize` can't be derived because `hex` requires the type to also implement `FromHex`. * feature(rpc): add suggestions from code review Co-authored-by: Janito Vaqueiro Ferreira Filho <janito.vff@gmail.com> * tests(rpc): make sure mempool has no requests in get_block test * fix(rpc): change height argument type in getblock method * fix(rpc): rustfmt * fix(rpc): replace panic * fix(rpc): change getblock response * fix(rpc): fix lightwalletd test * tests(rpc): add a getblock error test * fix(rpc): try another regex Co-authored-by: teor <teor@riseup.net> Co-authored-by: Janito Vaqueiro Ferreira Filho <janito.vff@gmail.com>
This commit is contained in:
parent
d8d3f6407c
commit
833560411f
|
|
@ -554,9 +554,9 @@ checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytemuck"
|
name = "bytemuck"
|
||||||
version = "1.7.3"
|
version = "1.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "439989e6b8c38d1b6570a384ef1e49c8848128f5a97f3914baef02920842712f"
|
checksum = "0e851ca7c24871e7336801608a4797d7376545b6928a10d32d75685687141ead"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "byteorder"
|
name = "byteorder"
|
||||||
|
|
@ -747,9 +747,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "color-eyre"
|
name = "color-eyre"
|
||||||
version = "0.6.0"
|
version = "0.6.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9d6ec7641ff3474b7593009c809db602c414cd97c7d47a78ed004162b74ff96c"
|
checksum = "8ebf286c900a6d5867aeff75cfee3192857bb7f24b547d4f0df2ed6baa812c90"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"backtrace",
|
"backtrace",
|
||||||
"color-spantrace 0.2.0",
|
"color-spantrace 0.2.0",
|
||||||
|
|
@ -1233,9 +1233,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ed25519"
|
name = "ed25519"
|
||||||
version = "1.3.0"
|
version = "1.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "74e1069e39f1454367eb2de793ed062fac4c35c2934b76a81d90dd9abcd28816"
|
checksum = "eed12bbf7b5312f8da1c2722bc06d8c6b12c2d86a7fb35a194c7f3e6fc2bbe39"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"signature",
|
"signature",
|
||||||
]
|
]
|
||||||
|
|
@ -1351,9 +1351,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "eyre"
|
name = "eyre"
|
||||||
version = "0.6.6"
|
version = "0.6.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bc225d8f637923fe585089fcf03e705c222131232d2c1fb622e84ecf725d0eb8"
|
checksum = "9289ed2c0440a6536e65119725cf91fc2c6b5e513bfd2e36e1134d7cca6ca12f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indenter",
|
"indenter",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
|
@ -1616,9 +1616,9 @@ checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "git2"
|
name = "git2"
|
||||||
version = "0.13.25"
|
version = "0.14.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f29229cc1b24c0e6062f6e742aa3e256492a5323365e5ed3413599f8a5eff7d6"
|
checksum = "6e7d3b96ec1fcaa8431cf04a4f1ef5caafe58d5cf7bcc31f09c1626adddb0ffe"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"libc",
|
"libc",
|
||||||
|
|
@ -1963,9 +1963,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "insta"
|
name = "insta"
|
||||||
version = "1.12.0"
|
version = "1.13.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f4c0c443f6dceb3a1cb7607c87501aa91e4b9c976044f725c2a74ca2152c91a4"
|
checksum = "30a7e1911532a662f6b08b68f884080850f2fd9544963c3ab23a5af42bda1eac"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"console",
|
"console",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
|
@ -1987,9 +1987,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ipnet"
|
name = "ipnet"
|
||||||
version = "2.3.1"
|
version = "2.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9"
|
checksum = "35e70ee094dc02fd9c13fdad4940090f22dbd6ac7c9e7094a46cf0232a50bc7c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itertools"
|
name = "itertools"
|
||||||
|
|
@ -2134,9 +2134,9 @@ checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libgit2-sys"
|
name = "libgit2-sys"
|
||||||
version = "0.12.26+1.3.0"
|
version = "0.13.1+1.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "19e1c899248e606fbfe68dcb31d8b0176ebab833b103824af31bddf4b7457494"
|
checksum = "43e598aa7a4faedf1ea1b4608f582b06f0f40211eec551b7ef36019ae3f62def"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"libc",
|
"libc",
|
||||||
|
|
@ -2187,9 +2187,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libz-sys"
|
name = "libz-sys"
|
||||||
version = "1.1.3"
|
version = "1.1.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "de5435b8549c16d423ed0c03dbaafe57cf6c3344744f1242520d59c9d8ecec66"
|
checksum = "df2bf61678a0a521c3f7daf815d2e6717d85a272a7dcd02c9768272b32bd1e2a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"libc",
|
"libc",
|
||||||
|
|
@ -2399,9 +2399,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "minreq"
|
name = "minreq"
|
||||||
version = "2.5.1"
|
version = "2.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "086dde2aacc3ce84b680e76ef4a60d77e75cb8109e5a508cc7ea81a86d65fd0d"
|
checksum = "4c785bc6027fd359756e538541c8624012ba3776d3d3fe123885643092ed4132"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"log",
|
"log",
|
||||||
|
|
@ -3355,9 +3355,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.2.10"
|
version = "0.2.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
|
checksum = "8380fe0152551244f0747b1bf41737e0f8a74f97a14ccefd1148187271634f3c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
]
|
]
|
||||||
|
|
@ -3447,9 +3447,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "retain_mut"
|
name = "retain_mut"
|
||||||
version = "0.1.6"
|
version = "0.1.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "51dd4445360338dab5116712bee1388dc727991d51969558a8882ab552e6db30"
|
checksum = "8c31b5c4033f8fdde8700e4657be2c497e7288f01515be52168c631e2e4d4086"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "retry-error"
|
name = "retry-error"
|
||||||
|
|
@ -3459,9 +3459,9 @@ checksum = "5f0cb6e2859e29280664e192b37e0a698cef381fec81783f9efa3e5b0ffbaf8f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rgb"
|
name = "rgb"
|
||||||
version = "0.8.31"
|
version = "0.8.32"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9a374af9a0e5fdcdd98c1c7b64f05004f9ea2555b6c75f211daa81268a3c50f1"
|
checksum = "e74fdc210d8f24a7dbfedc13b04ba5764f5232754ccebfdf5fff1bad791ccbc6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
]
|
]
|
||||||
|
|
@ -4006,9 +4006,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "siphasher"
|
name = "siphasher"
|
||||||
version = "0.3.9"
|
version = "0.3.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a86232ab60fa71287d7f2ddae4a7073f6b7aac33631c3015abb556f08c6d0a3e"
|
checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sketches-ddsketch"
|
name = "sketches-ddsketch"
|
||||||
|
|
@ -4206,9 +4206,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "termcolor"
|
name = "termcolor"
|
||||||
version = "1.1.2"
|
version = "1.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
|
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"winapi-util",
|
"winapi-util",
|
||||||
]
|
]
|
||||||
|
|
@ -4841,7 +4841,7 @@ dependencies = [
|
||||||
name = "tower-batch"
|
name = "tower-batch"
|
||||||
version = "0.2.21"
|
version = "0.2.21"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"color-eyre 0.6.0",
|
"color-eyre 0.6.1",
|
||||||
"ed25519-zebra",
|
"ed25519-zebra",
|
||||||
"futures",
|
"futures",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
|
|
@ -5614,7 +5614,7 @@ dependencies = [
|
||||||
"bs58",
|
"bs58",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"chrono",
|
"chrono",
|
||||||
"color-eyre 0.6.0",
|
"color-eyre 0.6.1",
|
||||||
"criterion",
|
"criterion",
|
||||||
"displaydoc",
|
"displaydoc",
|
||||||
"ed25519-zebra",
|
"ed25519-zebra",
|
||||||
|
|
@ -5666,7 +5666,7 @@ dependencies = [
|
||||||
"blake2b_simd 1.0.0",
|
"blake2b_simd 1.0.0",
|
||||||
"bls12_381",
|
"bls12_381",
|
||||||
"chrono",
|
"chrono",
|
||||||
"color-eyre 0.6.0",
|
"color-eyre 0.6.1",
|
||||||
"dirs",
|
"dirs",
|
||||||
"displaydoc",
|
"displaydoc",
|
||||||
"futures",
|
"futures",
|
||||||
|
|
@ -5762,6 +5762,7 @@ dependencies = [
|
||||||
"zebra-chain",
|
"zebra-chain",
|
||||||
"zebra-network",
|
"zebra-network",
|
||||||
"zebra-node-services",
|
"zebra-node-services",
|
||||||
|
"zebra-state",
|
||||||
"zebra-test",
|
"zebra-test",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -5784,7 +5785,7 @@ version = "1.0.0-beta.5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bincode",
|
"bincode",
|
||||||
"chrono",
|
"chrono",
|
||||||
"color-eyre 0.6.0",
|
"color-eyre 0.6.1",
|
||||||
"dirs",
|
"dirs",
|
||||||
"displaydoc",
|
"displaydoc",
|
||||||
"futures",
|
"futures",
|
||||||
|
|
@ -5841,7 +5842,7 @@ dependencies = [
|
||||||
name = "zebra-utils"
|
name = "zebra-utils"
|
||||||
version = "1.0.0-beta.5"
|
version = "1.0.0-beta.5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"color-eyre 0.6.0",
|
"color-eyre 0.6.1",
|
||||||
"hex",
|
"hex",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"structopt",
|
"structopt",
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ pub use commitment::{
|
||||||
pub use hash::Hash;
|
pub use hash::Hash;
|
||||||
pub use header::{BlockTimeError, CountedHeader, Header};
|
pub use header::{BlockTimeError, CountedHeader, Header};
|
||||||
pub use height::Height;
|
pub use height::Height;
|
||||||
pub use serialize::MAX_BLOCK_BYTES;
|
pub use serialize::{SerializedBlock, MAX_BLOCK_BYTES};
|
||||||
|
|
||||||
#[cfg(any(test, feature = "proptest-impl"))]
|
#[cfg(any(test, feature = "proptest-impl"))]
|
||||||
pub use arbitrary::LedgerState;
|
pub use arbitrary::LedgerState;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{convert::TryInto, io};
|
use std::{borrow::Borrow, convert::TryInto, io};
|
||||||
|
|
||||||
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||||
use chrono::{TimeZone, Utc};
|
use chrono::{TimeZone, Utc};
|
||||||
|
|
@ -135,3 +135,30 @@ impl ZcashDeserialize for Block {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A serialized block.
|
||||||
|
///
|
||||||
|
/// Stores bytes that are guaranteed to be deserializable into a [`Block`].
|
||||||
|
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||||
|
pub struct SerializedBlock {
|
||||||
|
bytes: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Build a [`SerializedBlock`] by serializing a block.
|
||||||
|
impl<B: Borrow<Block>> From<B> for SerializedBlock {
|
||||||
|
fn from(block: B) -> Self {
|
||||||
|
SerializedBlock {
|
||||||
|
bytes: block
|
||||||
|
.borrow()
|
||||||
|
.zcash_serialize_to_vec()
|
||||||
|
.expect("Writing to a `Vec` should never fail"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Access the serialized bytes of a [`SerializedBlock`].
|
||||||
|
impl AsRef<[u8]> for SerializedBlock {
|
||||||
|
fn as_ref(&self) -> &[u8] {
|
||||||
|
self.bytes.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,9 @@ edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
zebra-chain = { path = "../zebra-chain" }
|
zebra-chain = { path = "../zebra-chain" }
|
||||||
zebra-node-services = { path = "../zebra-node-services" }
|
|
||||||
|
|
||||||
zebra-network = { path = "../zebra-network" }
|
zebra-network = { path = "../zebra-network" }
|
||||||
|
zebra-node-services = { path = "../zebra-node-services" }
|
||||||
|
zebra-state = { path = "../zebra-state" }
|
||||||
|
|
||||||
futures = "0.3.21"
|
futures = "0.3.21"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,14 +6,15 @@
|
||||||
//! Some parts of the `zcashd` RPC documentation are outdated.
|
//! Some parts of the `zcashd` RPC documentation are outdated.
|
||||||
//! So this implementation follows the `lightwalletd` client implementation.
|
//! So this implementation follows the `lightwalletd` client implementation.
|
||||||
|
|
||||||
use futures::FutureExt;
|
use futures::{FutureExt, TryFutureExt};
|
||||||
use hex::FromHex;
|
use hex::FromHex;
|
||||||
use jsonrpc_core::{self, BoxFuture, Error, ErrorCode, Result};
|
use jsonrpc_core::{self, BoxFuture, Error, ErrorCode, Result};
|
||||||
use jsonrpc_derive::rpc;
|
use jsonrpc_derive::rpc;
|
||||||
use tower::{buffer::Buffer, ServiceExt};
|
use tower::{buffer::Buffer, Service, ServiceExt};
|
||||||
|
|
||||||
use zebra_chain::{
|
use zebra_chain::{
|
||||||
serialization::ZcashDeserialize,
|
block::SerializedBlock,
|
||||||
|
serialization::{SerializationError, ZcashDeserialize},
|
||||||
transaction::{self, Transaction},
|
transaction::{self, Transaction},
|
||||||
};
|
};
|
||||||
use zebra_network::constants::USER_AGENT;
|
use zebra_network::constants::USER_AGENT;
|
||||||
|
|
@ -72,38 +73,82 @@ pub trait Rpc {
|
||||||
&self,
|
&self,
|
||||||
raw_transaction_hex: String,
|
raw_transaction_hex: String,
|
||||||
) -> BoxFuture<Result<SentTransactionHash>>;
|
) -> BoxFuture<Result<SentTransactionHash>>;
|
||||||
|
|
||||||
|
/// getblock
|
||||||
|
///
|
||||||
|
/// Returns requested block by height, encoded as hex.
|
||||||
|
///
|
||||||
|
/// zcashd reference: <https://zcash.github.io/rpc/getblock.html>
|
||||||
|
///
|
||||||
|
/// Result:
|
||||||
|
/// {
|
||||||
|
/// "data": String, // The block encoded as hex
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// Note 1: We only expose the `data` field as lightwalletd uses the non-verbose
|
||||||
|
/// mode for all getblock calls: <https://github.com/zcash/lightwalletd/blob/v0.4.9/common/common.go#L232>
|
||||||
|
///
|
||||||
|
/// Note 2: `lightwalletd` only requests blocks by height, so we don't support
|
||||||
|
/// getting blocks by hash.
|
||||||
|
///
|
||||||
|
/// Note 3: The `verbosity` parameter is ignored but required in the call.
|
||||||
|
#[rpc(name = "getblock")]
|
||||||
|
fn get_block(&self, height: String, verbosity: u8) -> BoxFuture<Result<GetBlock>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// RPC method implementations.
|
/// RPC method implementations.
|
||||||
pub struct RpcImpl<Mempool>
|
pub struct RpcImpl<Mempool, State>
|
||||||
where
|
where
|
||||||
Mempool: tower::Service<mempool::Request, Response = mempool::Response, Error = BoxError>,
|
Mempool: Service<mempool::Request, Response = mempool::Response, Error = BoxError>,
|
||||||
|
State: Service<
|
||||||
|
zebra_state::Request,
|
||||||
|
Response = zebra_state::Response,
|
||||||
|
Error = zebra_state::BoxError,
|
||||||
|
>,
|
||||||
{
|
{
|
||||||
/// Zebra's application version.
|
/// Zebra's application version.
|
||||||
app_version: String,
|
app_version: String,
|
||||||
|
|
||||||
/// A handle to the mempool service.
|
/// A handle to the mempool service.
|
||||||
mempool: Buffer<Mempool, mempool::Request>,
|
mempool: Buffer<Mempool, mempool::Request>,
|
||||||
|
/// A handle to the state service.
|
||||||
|
state: Buffer<State, zebra_state::Request>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Mempool> RpcImpl<Mempool>
|
impl<Mempool, State> RpcImpl<Mempool, State>
|
||||||
where
|
where
|
||||||
Mempool: tower::Service<mempool::Request, Response = mempool::Response, Error = BoxError>,
|
Mempool: Service<mempool::Request, Response = mempool::Response, Error = BoxError>,
|
||||||
|
State: Service<
|
||||||
|
zebra_state::Request,
|
||||||
|
Response = zebra_state::Response,
|
||||||
|
Error = zebra_state::BoxError,
|
||||||
|
> + 'static,
|
||||||
|
State::Future: Send,
|
||||||
{
|
{
|
||||||
/// Create a new instance of the RPC handler.
|
/// Create a new instance of the RPC handler.
|
||||||
pub fn new(app_version: String, mempool: Buffer<Mempool, mempool::Request>) -> Self {
|
pub fn new(
|
||||||
|
app_version: String,
|
||||||
|
mempool: Buffer<Mempool, mempool::Request>,
|
||||||
|
state: Buffer<State, zebra_state::Request>,
|
||||||
|
) -> Self {
|
||||||
RpcImpl {
|
RpcImpl {
|
||||||
app_version,
|
app_version,
|
||||||
mempool,
|
mempool,
|
||||||
|
state,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Mempool> Rpc for RpcImpl<Mempool>
|
impl<Mempool, State> Rpc for RpcImpl<Mempool, State>
|
||||||
where
|
where
|
||||||
Mempool:
|
Mempool:
|
||||||
tower::Service<mempool::Request, Response = mempool::Response, Error = BoxError> + 'static,
|
tower::Service<mempool::Request, Response = mempool::Response, Error = BoxError> + 'static,
|
||||||
Mempool::Future: Send,
|
Mempool::Future: Send,
|
||||||
|
State: Service<
|
||||||
|
zebra_state::Request,
|
||||||
|
Response = zebra_state::Response,
|
||||||
|
Error = zebra_state::BoxError,
|
||||||
|
> + 'static,
|
||||||
|
State::Future: Send,
|
||||||
{
|
{
|
||||||
fn get_info(&self) -> Result<GetInfo> {
|
fn get_info(&self) -> Result<GetInfo> {
|
||||||
let response = GetInfo {
|
let response = GetInfo {
|
||||||
|
|
@ -169,6 +214,40 @@ where
|
||||||
}
|
}
|
||||||
.boxed()
|
.boxed()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_block(&self, height: String, _verbosity: u8) -> BoxFuture<Result<GetBlock>> {
|
||||||
|
let mut state = self.state.clone();
|
||||||
|
|
||||||
|
async move {
|
||||||
|
let height = height.parse().map_err(|error: SerializationError| Error {
|
||||||
|
code: ErrorCode::ServerError(0),
|
||||||
|
message: error.to_string(),
|
||||||
|
data: None,
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let request = zebra_state::Request::Block(zebra_state::HashOrHeight::Height(height));
|
||||||
|
let response = state
|
||||||
|
.ready()
|
||||||
|
.and_then(|service| service.call(request))
|
||||||
|
.await
|
||||||
|
.map_err(|error| Error {
|
||||||
|
code: ErrorCode::ServerError(0),
|
||||||
|
message: error.to_string(),
|
||||||
|
data: None,
|
||||||
|
})?;
|
||||||
|
|
||||||
|
match response {
|
||||||
|
zebra_state::Response::Block(Some(block)) => Ok(GetBlock(block.into())),
|
||||||
|
zebra_state::Response::Block(None) => Err(Error {
|
||||||
|
code: ErrorCode::ServerError(0),
|
||||||
|
message: "Block not found".to_string(),
|
||||||
|
data: None,
|
||||||
|
}),
|
||||||
|
_ => unreachable!("unmatched response to a block request"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.boxed()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(serde::Serialize, serde::Deserialize)]
|
#[derive(serde::Serialize, serde::Deserialize)]
|
||||||
|
|
@ -190,3 +269,7 @@ pub struct GetBlockChainInfo {
|
||||||
///
|
///
|
||||||
/// A JSON string with the transaction hash in hexadecimal.
|
/// A JSON string with the transaction hash in hexadecimal.
|
||||||
pub struct SentTransactionHash(#[serde(with = "hex")] transaction::Hash);
|
pub struct SentTransactionHash(#[serde(with = "hex")] transaction::Hash);
|
||||||
|
|
||||||
|
#[derive(serde::Serialize)]
|
||||||
|
/// Response to a `getblock` RPC request.
|
||||||
|
pub struct GetBlock(#[serde(with = "hex")] SerializedBlock);
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,8 @@ proptest! {
|
||||||
|
|
||||||
runtime.block_on(async move {
|
runtime.block_on(async move {
|
||||||
let mut mempool = MockService::build().for_prop_tests();
|
let mut mempool = MockService::build().for_prop_tests();
|
||||||
let rpc = RpcImpl::new("RPC test".to_owned(), Buffer::new(mempool.clone(), 1));
|
let mut state = MockService::build().for_prop_tests();
|
||||||
|
let rpc = RpcImpl::new("RPC test".to_owned(), Buffer::new(mempool.clone(), 1), Buffer::new(state.clone(), 1));
|
||||||
let hash = SentTransactionHash(transaction.hash());
|
let hash = SentTransactionHash(transaction.hash());
|
||||||
|
|
||||||
let transaction_bytes = transaction
|
let transaction_bytes = transaction
|
||||||
|
|
@ -39,6 +40,8 @@ proptest! {
|
||||||
.await?
|
.await?
|
||||||
.respond(response);
|
.respond(response);
|
||||||
|
|
||||||
|
state.expect_no_requests().await?;
|
||||||
|
|
||||||
let result = send_task
|
let result = send_task
|
||||||
.await
|
.await
|
||||||
.expect("Sending raw transactions should not panic");
|
.expect("Sending raw transactions should not panic");
|
||||||
|
|
@ -58,7 +61,9 @@ proptest! {
|
||||||
|
|
||||||
runtime.block_on(async move {
|
runtime.block_on(async move {
|
||||||
let mut mempool = MockService::build().for_prop_tests();
|
let mut mempool = MockService::build().for_prop_tests();
|
||||||
let rpc = RpcImpl::new("RPC test".to_owned(), Buffer::new(mempool.clone(), 1));
|
let mut state = MockService::build().for_prop_tests();
|
||||||
|
|
||||||
|
let rpc = RpcImpl::new("RPC test".to_owned(), Buffer::new(mempool.clone(), 1), Buffer::new(state.clone(), 1));
|
||||||
|
|
||||||
let transaction_bytes = transaction
|
let transaction_bytes = transaction
|
||||||
.zcash_serialize_to_vec()
|
.zcash_serialize_to_vec()
|
||||||
|
|
@ -75,6 +80,9 @@ proptest! {
|
||||||
.await?
|
.await?
|
||||||
.respond(Err(DummyError));
|
.respond(Err(DummyError));
|
||||||
|
|
||||||
|
state.expect_no_requests().await?;
|
||||||
|
|
||||||
|
|
||||||
let result = send_task
|
let result = send_task
|
||||||
.await
|
.await
|
||||||
.expect("Sending raw transactions should not panic");
|
.expect("Sending raw transactions should not panic");
|
||||||
|
|
@ -101,7 +109,9 @@ proptest! {
|
||||||
|
|
||||||
runtime.block_on(async move {
|
runtime.block_on(async move {
|
||||||
let mut mempool = MockService::build().for_prop_tests();
|
let mut mempool = MockService::build().for_prop_tests();
|
||||||
let rpc = RpcImpl::new("RPC test".to_owned(), Buffer::new(mempool.clone(), 1));
|
let mut state = MockService::build().for_prop_tests();
|
||||||
|
|
||||||
|
let rpc = RpcImpl::new("RPC test".to_owned(), Buffer::new(mempool.clone(), 1), Buffer::new(state.clone(), 1));
|
||||||
|
|
||||||
let transaction_bytes = transaction
|
let transaction_bytes = transaction
|
||||||
.zcash_serialize_to_vec()
|
.zcash_serialize_to_vec()
|
||||||
|
|
@ -119,6 +129,8 @@ proptest! {
|
||||||
.await?
|
.await?
|
||||||
.respond(response);
|
.respond(response);
|
||||||
|
|
||||||
|
state.expect_no_requests().await?;
|
||||||
|
|
||||||
let result = send_task
|
let result = send_task
|
||||||
.await
|
.await
|
||||||
.expect("Sending raw transactions should not panic");
|
.expect("Sending raw transactions should not panic");
|
||||||
|
|
@ -152,11 +164,14 @@ proptest! {
|
||||||
|
|
||||||
runtime.block_on(async move {
|
runtime.block_on(async move {
|
||||||
let mut mempool = MockService::build().for_prop_tests();
|
let mut mempool = MockService::build().for_prop_tests();
|
||||||
let rpc = RpcImpl::new("RPC test".to_owned(), Buffer::new(mempool.clone(), 1));
|
let mut state = MockService::build().for_prop_tests();
|
||||||
|
|
||||||
|
let rpc = RpcImpl::new("RPC test".to_owned(), Buffer::new(mempool.clone(), 1), Buffer::new(state.clone(), 1));
|
||||||
|
|
||||||
let send_task = tokio::spawn(rpc.send_raw_transaction(non_hex_string));
|
let send_task = tokio::spawn(rpc.send_raw_transaction(non_hex_string));
|
||||||
|
|
||||||
mempool.expect_no_requests().await?;
|
mempool.expect_no_requests().await?;
|
||||||
|
state.expect_no_requests().await?;
|
||||||
|
|
||||||
let result = send_task
|
let result = send_task
|
||||||
.await
|
.await
|
||||||
|
|
@ -193,11 +208,14 @@ proptest! {
|
||||||
|
|
||||||
runtime.block_on(async move {
|
runtime.block_on(async move {
|
||||||
let mut mempool = MockService::build().for_prop_tests();
|
let mut mempool = MockService::build().for_prop_tests();
|
||||||
let rpc = RpcImpl::new("RPC test".to_owned(), Buffer::new(mempool.clone(), 1));
|
let mut state = MockService::build().for_prop_tests();
|
||||||
|
|
||||||
|
let rpc = RpcImpl::new("RPC test".to_owned(), Buffer::new(mempool.clone(), 1), Buffer::new(state.clone(), 1));
|
||||||
|
|
||||||
let send_task = tokio::spawn(rpc.send_raw_transaction(hex::encode(random_bytes)));
|
let send_task = tokio::spawn(rpc.send_raw_transaction(hex::encode(random_bytes)));
|
||||||
|
|
||||||
mempool.expect_no_requests().await?;
|
mempool.expect_no_requests().await?;
|
||||||
|
state.expect_no_requests().await?;
|
||||||
|
|
||||||
let result = send_task
|
let result = send_task
|
||||||
.await
|
.await
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
//! Fixed test vectors for RPC methods.
|
//! Fixed test vectors for RPC methods.
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use tower::buffer::Buffer;
|
use tower::buffer::Buffer;
|
||||||
|
|
||||||
|
use zebra_chain::{block::Block, parameters::Network, serialization::ZcashDeserializeInto};
|
||||||
use zebra_network::constants::USER_AGENT;
|
use zebra_network::constants::USER_AGENT;
|
||||||
use zebra_node_services::BoxError;
|
use zebra_node_services::BoxError;
|
||||||
use zebra_test::mock_service::MockService;
|
use zebra_test::mock_service::MockService;
|
||||||
|
|
@ -13,10 +16,12 @@ async fn rpc_getinfo() {
|
||||||
zebra_test::init();
|
zebra_test::init();
|
||||||
|
|
||||||
let mut mempool: MockService<_, _, _, BoxError> = MockService::build().for_unit_tests();
|
let mut mempool: MockService<_, _, _, BoxError> = MockService::build().for_unit_tests();
|
||||||
|
let mut state = MockService::build().for_unit_tests();
|
||||||
|
|
||||||
let rpc = RpcImpl::new(
|
let rpc = RpcImpl::new(
|
||||||
"Zebra version test".to_string(),
|
"Zebra version test".to_string(),
|
||||||
Buffer::new(mempool.clone(), 1),
|
Buffer::new(mempool.clone(), 1),
|
||||||
|
Buffer::new(state.clone(), 1),
|
||||||
);
|
);
|
||||||
|
|
||||||
let get_info = rpc.get_info().expect("We should have a GetInfo struct");
|
let get_info = rpc.get_info().expect("We should have a GetInfo struct");
|
||||||
|
|
@ -30,4 +35,66 @@ async fn rpc_getinfo() {
|
||||||
assert_eq!(get_info.subversion, USER_AGENT);
|
assert_eq!(get_info.subversion, USER_AGENT);
|
||||||
|
|
||||||
mempool.expect_no_requests().await;
|
mempool.expect_no_requests().await;
|
||||||
|
state.expect_no_requests().await;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn rpc_getblock() {
|
||||||
|
zebra_test::init();
|
||||||
|
|
||||||
|
// Number of blocks to populate state with
|
||||||
|
const NUMBER_OF_BLOCKS: u32 = 10;
|
||||||
|
|
||||||
|
// Put the first `NUMBER_OF_BLOCKS` blocks in a vector
|
||||||
|
let blocks: Vec<Arc<Block>> = zebra_test::vectors::MAINNET_BLOCKS
|
||||||
|
.range(0..=NUMBER_OF_BLOCKS)
|
||||||
|
.map(|(_, block_bytes)| block_bytes.zcash_deserialize_into::<Arc<Block>>().unwrap())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut mempool: MockService<_, _, _, BoxError> = MockService::build().for_unit_tests();
|
||||||
|
// Create a populated state service
|
||||||
|
let state = zebra_state::populated_state(blocks.clone(), Network::Mainnet).await;
|
||||||
|
|
||||||
|
// Init RPC
|
||||||
|
let rpc = RpcImpl {
|
||||||
|
app_version: "Zebra version test".to_string(),
|
||||||
|
mempool: Buffer::new(mempool.clone(), 1),
|
||||||
|
state,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Make calls and check response
|
||||||
|
for (i, block) in blocks.into_iter().enumerate() {
|
||||||
|
let get_block = rpc
|
||||||
|
.get_block(i.to_string(), 0u8)
|
||||||
|
.await
|
||||||
|
.expect("We should have a GetBlock struct");
|
||||||
|
|
||||||
|
assert_eq!(get_block.0, block.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
mempool.expect_no_requests().await;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn rpc_getblock_error() {
|
||||||
|
zebra_test::init();
|
||||||
|
|
||||||
|
let mut mempool: MockService<_, _, _, BoxError> = MockService::build().for_unit_tests();
|
||||||
|
let mut state = MockService::build().for_unit_tests();
|
||||||
|
|
||||||
|
// Init RPC
|
||||||
|
let rpc = RpcImpl {
|
||||||
|
app_version: "Zebra version test".to_string(),
|
||||||
|
mempool: Buffer::new(mempool.clone(), 1),
|
||||||
|
state: Buffer::new(state.clone(), 1),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Make sure we get an error if Zebra can't parse the block height.
|
||||||
|
assert!(rpc
|
||||||
|
.get_block("not parsable as height".to_string(), 0u8)
|
||||||
|
.await
|
||||||
|
.is_err());
|
||||||
|
|
||||||
|
mempool.expect_no_requests().await;
|
||||||
|
state.expect_no_requests().await;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
use jsonrpc_core;
|
use jsonrpc_core;
|
||||||
use jsonrpc_http_server::ServerBuilder;
|
use jsonrpc_http_server::ServerBuilder;
|
||||||
use tower::buffer::Buffer;
|
use tower::{buffer::Buffer, Service};
|
||||||
use tracing::*;
|
use tracing::*;
|
||||||
use tracing_futures::Instrument;
|
use tracing_futures::Instrument;
|
||||||
|
|
||||||
|
|
@ -26,21 +26,28 @@ pub struct RpcServer;
|
||||||
|
|
||||||
impl RpcServer {
|
impl RpcServer {
|
||||||
/// Start a new RPC server endpoint
|
/// Start a new RPC server endpoint
|
||||||
pub fn spawn<Mempool>(
|
pub fn spawn<Mempool, State>(
|
||||||
config: Config,
|
config: Config,
|
||||||
app_version: String,
|
app_version: String,
|
||||||
mempool: Buffer<Mempool, mempool::Request>,
|
mempool: Buffer<Mempool, mempool::Request>,
|
||||||
|
state: Buffer<State, zebra_state::Request>,
|
||||||
) -> tokio::task::JoinHandle<()>
|
) -> tokio::task::JoinHandle<()>
|
||||||
where
|
where
|
||||||
Mempool: tower::Service<mempool::Request, Response = mempool::Response, Error = BoxError>
|
Mempool: tower::Service<mempool::Request, Response = mempool::Response, Error = BoxError>
|
||||||
+ 'static,
|
+ 'static,
|
||||||
Mempool::Future: Send,
|
Mempool::Future: Send,
|
||||||
|
State: Service<
|
||||||
|
zebra_state::Request,
|
||||||
|
Response = zebra_state::Response,
|
||||||
|
Error = zebra_state::BoxError,
|
||||||
|
> + 'static,
|
||||||
|
State::Future: Send,
|
||||||
{
|
{
|
||||||
if let Some(listen_addr) = config.listen_addr {
|
if let Some(listen_addr) = config.listen_addr {
|
||||||
info!("Trying to open RPC endpoint at {}...", listen_addr,);
|
info!("Trying to open RPC endpoint at {}...", listen_addr,);
|
||||||
|
|
||||||
// Initialize the rpc methods with the zebra version
|
// Initialize the rpc methods with the zebra version
|
||||||
let rpc_impl = RpcImpl::new(app_version, mempool);
|
let rpc_impl = RpcImpl::new(app_version, mempool, state);
|
||||||
|
|
||||||
// Create handler compatible with V1 and V2 RPC protocols
|
// Create handler compatible with V1 and V2 RPC protocols
|
||||||
let mut io =
|
let mut io =
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ pub use service::{
|
||||||
#[cfg(any(test, feature = "proptest-impl"))]
|
#[cfg(any(test, feature = "proptest-impl"))]
|
||||||
pub use service::{
|
pub use service::{
|
||||||
chain_tip::{ChainTipBlock, ChainTipSender},
|
chain_tip::{ChainTipBlock, ChainTipSender},
|
||||||
init_test,
|
init_test, populated_state,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) use request::ContextuallyValidBlock;
|
pub(crate) use request::ContextuallyValidBlock;
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,9 @@ use std::{
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
|
|
||||||
use futures::future::FutureExt;
|
use futures::{future::FutureExt, stream::FuturesUnordered};
|
||||||
use tokio::sync::oneshot;
|
use tokio::sync::oneshot;
|
||||||
use tower::{util::BoxService, Service};
|
use tower::{util::BoxService, Service, ServiceExt};
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
|
|
||||||
#[cfg(any(test, feature = "proptest-impl"))]
|
#[cfg(any(test, feature = "proptest-impl"))]
|
||||||
|
|
@ -843,6 +843,33 @@ pub fn init_test(network: Network) -> Buffer<BoxService<Request, Response, BoxEr
|
||||||
Buffer::new(BoxService::new(state_service), 1)
|
Buffer::new(BoxService::new(state_service), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Initialize a state service with blocks.
|
||||||
|
#[cfg(any(test, feature = "proptest-impl"))]
|
||||||
|
pub async fn populated_state(
|
||||||
|
blocks: impl IntoIterator<Item = Arc<Block>>,
|
||||||
|
network: Network,
|
||||||
|
) -> Buffer<BoxService<Request, Response, BoxError>, Request> {
|
||||||
|
let requests = blocks
|
||||||
|
.into_iter()
|
||||||
|
.map(|block| Request::CommitFinalizedBlock(block.into()));
|
||||||
|
|
||||||
|
let mut state = init_test(network);
|
||||||
|
|
||||||
|
let mut responses = FuturesUnordered::new();
|
||||||
|
|
||||||
|
for request in requests {
|
||||||
|
let rsp = state.ready().await.unwrap().call(request);
|
||||||
|
responses.push(rsp);
|
||||||
|
}
|
||||||
|
|
||||||
|
use futures::StreamExt;
|
||||||
|
while let Some(rsp) = responses.next().await {
|
||||||
|
rsp.expect("blocks should commit just fine");
|
||||||
|
}
|
||||||
|
|
||||||
|
state
|
||||||
|
}
|
||||||
|
|
||||||
/// Check if zebra is following a legacy chain and return an error if so.
|
/// Check if zebra is following a legacy chain and return an error if so.
|
||||||
fn legacy_chain_check<I>(
|
fn legacy_chain_check<I>(
|
||||||
nu5_activation_height: block::Height,
|
nu5_activation_height: block::Height,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
use std::{convert::TryInto, env, sync::Arc};
|
use std::{convert::TryInto, env, sync::Arc};
|
||||||
|
|
||||||
use futures::stream::FuturesUnordered;
|
use tower::{buffer::Buffer, util::BoxService};
|
||||||
use tower::{buffer::Buffer, util::BoxService, Service, ServiceExt};
|
|
||||||
|
|
||||||
use zebra_chain::{
|
use zebra_chain::{
|
||||||
block::{self, Block, CountedHeader},
|
block::{self, Block, CountedHeader},
|
||||||
|
|
@ -17,38 +16,13 @@ use zebra_test::{prelude::*, transcript::Transcript};
|
||||||
use crate::{
|
use crate::{
|
||||||
arbitrary::Prepare,
|
arbitrary::Prepare,
|
||||||
constants, init_test,
|
constants, init_test,
|
||||||
service::{chain_tip::TipAction, StateService},
|
service::{chain_tip::TipAction, populated_state, StateService},
|
||||||
tests::setup::{partial_nu5_chain_strategy, transaction_v4_from_coinbase},
|
tests::setup::{partial_nu5_chain_strategy, transaction_v4_from_coinbase},
|
||||||
BoxError, Config, FinalizedBlock, PreparedBlock, Request, Response,
|
BoxError, Config, FinalizedBlock, PreparedBlock, Request, Response,
|
||||||
};
|
};
|
||||||
|
|
||||||
const LAST_BLOCK_HEIGHT: u32 = 10;
|
const LAST_BLOCK_HEIGHT: u32 = 10;
|
||||||
|
|
||||||
async fn populated_state(
|
|
||||||
blocks: impl IntoIterator<Item = Arc<Block>>,
|
|
||||||
) -> Buffer<BoxService<Request, Response, BoxError>, Request> {
|
|
||||||
let requests = blocks
|
|
||||||
.into_iter()
|
|
||||||
.map(|block| Request::CommitFinalizedBlock(block.into()));
|
|
||||||
|
|
||||||
let network = Network::Mainnet;
|
|
||||||
let mut state = init_test(network);
|
|
||||||
|
|
||||||
let mut responses = FuturesUnordered::new();
|
|
||||||
|
|
||||||
for request in requests {
|
|
||||||
let rsp = state.ready().await.unwrap().call(request);
|
|
||||||
responses.push(rsp);
|
|
||||||
}
|
|
||||||
|
|
||||||
use futures::StreamExt;
|
|
||||||
while let Some(rsp) = responses.next().await {
|
|
||||||
rsp.expect("blocks should commit just fine");
|
|
||||||
}
|
|
||||||
|
|
||||||
state
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn test_populated_state_responds_correctly(
|
async fn test_populated_state_responds_correctly(
|
||||||
mut state: Buffer<BoxService<Request, Response, BoxError>, Request>,
|
mut state: Buffer<BoxService<Request, Response, BoxError>, Request>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
|
|
@ -222,7 +196,7 @@ async fn test_populated_state_responds_correctly(
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn populate_and_check(blocks: Vec<Arc<Block>>) -> Result<()> {
|
async fn populate_and_check(blocks: Vec<Arc<Block>>) -> Result<()> {
|
||||||
let state = populated_state(blocks).await;
|
let state = populated_state(blocks, Network::Mainnet).await;
|
||||||
test_populated_state_responds_correctly(state).await?;
|
test_populated_state_responds_correctly(state).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -155,8 +155,12 @@ impl StartCmd {
|
||||||
.service(mempool);
|
.service(mempool);
|
||||||
|
|
||||||
// Launch RPC server
|
// Launch RPC server
|
||||||
let rpc_task_handle =
|
let rpc_task_handle = RpcServer::spawn(
|
||||||
RpcServer::spawn(config.rpc, app_version().to_string(), mempool.clone());
|
config.rpc,
|
||||||
|
app_version().to_string(),
|
||||||
|
mempool.clone(),
|
||||||
|
state.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
let setup_data = InboundSetupData {
|
let setup_data = InboundSetupData {
|
||||||
address_book,
|
address_book,
|
||||||
|
|
|
||||||
|
|
@ -1693,7 +1693,7 @@ fn lightwalletd_integration() -> Result<()> {
|
||||||
// zcash/lightwalletd calls getbestblockhash here, but
|
// zcash/lightwalletd calls getbestblockhash here, but
|
||||||
// adityapk00/lightwalletd calls getblock
|
// adityapk00/lightwalletd calls getblock
|
||||||
let result =
|
let result =
|
||||||
lightwalletd.expect_stdout_line_matches("Method not found.*error zcashd getblock rpc");
|
lightwalletd.expect_stdout_line_matches("Block hash changed, clearing mempool clients");
|
||||||
let (_, zebrad) = zebrad.kill_on_error(result)?;
|
let (_, zebrad) = zebrad.kill_on_error(result)?;
|
||||||
|
|
||||||
// zcash/lightwalletd exits with a fatal error here.
|
// zcash/lightwalletd exits with a fatal error here.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue