Merge pull request #6533 from str4d/6397-cxx-rust-streams
Expand `CppStream` to cover all `Stream`-like C++ types
This commit is contained in:
commit
3ef6e96fa6
|
@ -284,6 +284,7 @@ BITCOIN_CORE_H = \
|
|||
serialize.h \
|
||||
spentindex.h \
|
||||
streams.h \
|
||||
streams_rust.h \
|
||||
support/allocators/secure.h \
|
||||
support/allocators/zeroafterfree.h \
|
||||
support/cleanse.h \
|
||||
|
@ -527,6 +528,7 @@ libbitcoin_common_a_SOURCES = \
|
|||
script/script_error.cpp \
|
||||
script/sign.cpp \
|
||||
script/standard.cpp \
|
||||
streams_rust.cpp \
|
||||
transaction_builder.cpp \
|
||||
util/test.cpp \
|
||||
warnings.cpp \
|
||||
|
|
|
@ -132,6 +132,11 @@ public:
|
|||
int GetType() const { return nType; }
|
||||
int GetVersion() const { return nVersion; }
|
||||
|
||||
void write_u8(const unsigned char* pch, size_t nSize)
|
||||
{
|
||||
ctx.Write(pch, nSize);
|
||||
}
|
||||
|
||||
void write(const char *pch, size_t size) {
|
||||
ctx.Write((const unsigned char*)pch, size);
|
||||
}
|
||||
|
|
|
@ -19,16 +19,35 @@ use crate::{
|
|||
new_bundle_assembler, BatchValidator, Bundle as SaplingBundle,
|
||||
BundleAssembler as SaplingBundleAssembler, Prover, Verifier,
|
||||
},
|
||||
streams::{
|
||||
from_auto_file, from_buffered_file, from_data, from_hash_writer, from_size_computer,
|
||||
CppStream,
|
||||
},
|
||||
wallet_scanner::{init_batch_scanner, BatchResult, BatchScanner},
|
||||
};
|
||||
|
||||
#[cxx::bridge]
|
||||
pub(crate) mod ffi {
|
||||
extern "C++" {
|
||||
include!("hash.h");
|
||||
include!("streams.h");
|
||||
|
||||
#[cxx_name = "RustDataStream"]
|
||||
type RustStream = crate::streams::ffi::RustStream;
|
||||
type CAutoFile = crate::streams::ffi::CAutoFile;
|
||||
type CBufferedFile = crate::streams::ffi::CBufferedFile;
|
||||
type CHashWriter = crate::streams::ffi::CHashWriter;
|
||||
type CSizeComputer = crate::streams::ffi::CSizeComputer;
|
||||
}
|
||||
#[namespace = "stream"]
|
||||
extern "Rust" {
|
||||
type CppStream<'a>;
|
||||
|
||||
fn from_data(stream: Pin<&mut RustStream>) -> Box<CppStream<'_>>;
|
||||
fn from_auto_file(file: Pin<&mut CAutoFile>) -> Box<CppStream<'_>>;
|
||||
fn from_buffered_file(file: Pin<&mut CBufferedFile>) -> Box<CppStream<'_>>;
|
||||
fn from_hash_writer(writer: Pin<&mut CHashWriter>) -> Box<CppStream<'_>>;
|
||||
fn from_size_computer(sc: Pin<&mut CSizeComputer>) -> Box<CppStream<'_>>;
|
||||
}
|
||||
|
||||
#[namespace = "consensus"]
|
||||
|
@ -201,9 +220,9 @@ pub(crate) mod ffi {
|
|||
fn orchard_empty_root() -> [u8; 32];
|
||||
fn new_orchard() -> Box<Orchard>;
|
||||
fn box_clone(self: &Orchard) -> Box<Orchard>;
|
||||
fn parse_orchard(stream: Pin<&mut RustStream>) -> Result<Box<Orchard>>;
|
||||
fn serialize(self: &Orchard, stream: Pin<&mut RustStream>) -> Result<()>;
|
||||
fn serialize_legacy(self: &Orchard, stream: Pin<&mut RustStream>) -> Result<()>;
|
||||
fn parse_orchard(reader: &mut CppStream<'_>) -> Result<Box<Orchard>>;
|
||||
fn serialize(self: &Orchard, writer: &mut CppStream<'_>) -> Result<()>;
|
||||
fn serialize_legacy(self: &Orchard, writer: &mut CppStream<'_>) -> Result<()>;
|
||||
fn dynamic_memory_usage(self: &Orchard) -> usize;
|
||||
fn root(self: &Orchard) -> [u8; 32];
|
||||
fn size(self: &Orchard) -> u64;
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use core::mem::size_of_val;
|
||||
use core::pin::Pin;
|
||||
|
||||
use incrementalmerkletree::{bridgetree, Altitude, Frontier, Hashable};
|
||||
use orchard::tree::MerkleHashOrchard;
|
||||
|
@ -9,7 +8,7 @@ use zcash_primitives::merkle_tree::{
|
|||
CommitmentTree, HashSer,
|
||||
};
|
||||
|
||||
use crate::{bridge::ffi, orchard_bundle, streams::CppStream, wallet::Wallet};
|
||||
use crate::{orchard_bundle, streams::CppStream, wallet::Wallet};
|
||||
|
||||
pub const MERKLE_DEPTH: u8 = 32;
|
||||
|
||||
|
@ -26,9 +25,7 @@ impl<H: Copy + Hashable + HashSer> MerkleFrontier<H> {
|
|||
}
|
||||
|
||||
/// Attempts to parse a Merkle frontier from the given C++ stream.
|
||||
pub(crate) fn parse(stream: Pin<&mut ffi::RustStream>) -> Result<Box<Self>, String> {
|
||||
let reader = CppStream::from(stream);
|
||||
|
||||
pub(crate) fn parse(reader: &mut CppStream<'_>) -> Result<Box<Self>, String> {
|
||||
match read_frontier_v1(reader) {
|
||||
Ok(parsed) => Ok(Box::new(MerkleFrontier(parsed))),
|
||||
Err(e) => Err(format!("Failed to parse v5 Merkle frontier: {}", e)),
|
||||
|
@ -36,15 +33,13 @@ impl<H: Copy + Hashable + HashSer> MerkleFrontier<H> {
|
|||
}
|
||||
|
||||
/// Serializes the frontier to the given C++ stream.
|
||||
pub(crate) fn serialize(&self, stream: Pin<&mut ffi::RustStream>) -> Result<(), String> {
|
||||
let writer = CppStream::from(stream);
|
||||
pub(crate) fn serialize(&self, writer: &mut CppStream<'_>) -> Result<(), String> {
|
||||
write_frontier_v1(writer, &self.0)
|
||||
.map_err(|e| format!("Failed to serialize v5 Merkle frontier: {}", e))
|
||||
}
|
||||
|
||||
/// Serializes the frontier to the given C++ stream in the legacy frontier encoding.
|
||||
pub(crate) fn serialize_legacy(&self, stream: Pin<&mut ffi::RustStream>) -> Result<(), String> {
|
||||
let writer = CppStream::from(stream);
|
||||
pub(crate) fn serialize_legacy(&self, writer: &mut CppStream<'_>) -> Result<(), String> {
|
||||
let commitment_tree = CommitmentTree::from_frontier(&self.0);
|
||||
commitment_tree.write(writer).map_err(|e| {
|
||||
format!(
|
||||
|
@ -93,8 +88,8 @@ pub(crate) fn new_orchard() -> Box<Orchard> {
|
|||
}
|
||||
|
||||
/// Attempts to parse an Orchard Merkle frontier from the given C++ stream.
|
||||
pub(crate) fn parse_orchard(stream: Pin<&mut ffi::RustStream>) -> Result<Box<Orchard>, String> {
|
||||
Orchard::parse(stream)
|
||||
pub(crate) fn parse_orchard(reader: &mut CppStream<'_>) -> Result<Box<Orchard>, String> {
|
||||
Orchard::parse(reader)
|
||||
}
|
||||
|
||||
pub(crate) struct OrchardWallet;
|
||||
|
|
|
@ -4,41 +4,116 @@ use std::pin::Pin;
|
|||
#[cxx::bridge]
|
||||
pub(crate) mod ffi {
|
||||
extern "C++" {
|
||||
include!("hash.h");
|
||||
include!("streams.h");
|
||||
|
||||
#[cxx_name = "RustDataStream"]
|
||||
type RustStream;
|
||||
|
||||
unsafe fn read_u8(self: Pin<&mut RustStream>, pch: *mut u8, nSize: usize) -> Result<()>;
|
||||
unsafe fn write_u8(self: Pin<&mut RustStream>, pch: *const u8, nSize: usize) -> Result<()>;
|
||||
|
||||
type CAutoFile;
|
||||
unsafe fn read_u8(self: Pin<&mut CAutoFile>, pch: *mut u8, nSize: usize) -> Result<()>;
|
||||
unsafe fn write_u8(self: Pin<&mut CAutoFile>, pch: *const u8, nSize: usize) -> Result<()>;
|
||||
|
||||
type CBufferedFile;
|
||||
unsafe fn read_u8(self: Pin<&mut CBufferedFile>, pch: *mut u8, nSize: usize) -> Result<()>;
|
||||
|
||||
type CHashWriter;
|
||||
unsafe fn write_u8(self: Pin<&mut CHashWriter>, pch: *const u8, nSize: usize)
|
||||
-> Result<()>;
|
||||
|
||||
type CSizeComputer;
|
||||
unsafe fn write_u8(
|
||||
self: Pin<&mut CSizeComputer>,
|
||||
pch: *const u8,
|
||||
nSize: usize,
|
||||
) -> Result<()>;
|
||||
}
|
||||
|
||||
impl UniquePtr<RustStream> {}
|
||||
impl UniquePtr<CAutoFile> {}
|
||||
impl UniquePtr<CBufferedFile> {}
|
||||
impl UniquePtr<CHashWriter> {}
|
||||
impl UniquePtr<CSizeComputer> {}
|
||||
}
|
||||
|
||||
pub struct CppStream<'a> {
|
||||
inner: Pin<&'a mut ffi::RustStream>,
|
||||
pub(crate) fn from_data(stream: Pin<&mut ffi::RustStream>) -> Box<CppStream<'_>> {
|
||||
Box::new(CppStream::Data(stream))
|
||||
}
|
||||
|
||||
impl<'a> From<Pin<&'a mut ffi::RustStream>> for CppStream<'a> {
|
||||
fn from(inner: Pin<&'a mut ffi::RustStream>) -> Self {
|
||||
Self { inner }
|
||||
}
|
||||
pub(crate) fn from_auto_file(file: Pin<&mut ffi::CAutoFile>) -> Box<CppStream<'_>> {
|
||||
Box::new(CppStream::AutoFile(file))
|
||||
}
|
||||
|
||||
pub(crate) fn from_buffered_file(file: Pin<&mut ffi::CBufferedFile>) -> Box<CppStream<'_>> {
|
||||
Box::new(CppStream::BufferedFile(file))
|
||||
}
|
||||
|
||||
pub(crate) fn from_hash_writer(writer: Pin<&mut ffi::CHashWriter>) -> Box<CppStream<'_>> {
|
||||
Box::new(CppStream::Hash(writer))
|
||||
}
|
||||
|
||||
pub(crate) fn from_size_computer(sc: Pin<&mut ffi::CSizeComputer>) -> Box<CppStream<'_>> {
|
||||
Box::new(CppStream::Size(sc))
|
||||
}
|
||||
|
||||
pub(crate) enum CppStream<'a> {
|
||||
Data(Pin<&'a mut ffi::RustStream>),
|
||||
AutoFile(Pin<&'a mut ffi::CAutoFile>),
|
||||
BufferedFile(Pin<&'a mut ffi::CBufferedFile>),
|
||||
Hash(Pin<&'a mut ffi::CHashWriter>),
|
||||
Size(Pin<&'a mut ffi::CSizeComputer>),
|
||||
}
|
||||
|
||||
impl<'a> io::Read for CppStream<'a> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
unsafe { self.inner.as_mut().read_u8(buf.as_mut_ptr(), buf.len()) }
|
||||
.map(|()| buf.len())
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))
|
||||
let pch = buf.as_mut_ptr();
|
||||
let len = buf.len();
|
||||
match self {
|
||||
CppStream::Data(inner) => unsafe { inner.as_mut().read_u8(pch, len) }
|
||||
.map(|()| buf.len())
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::Other, e)),
|
||||
CppStream::AutoFile(inner) => unsafe { inner.as_mut().read_u8(pch, len) }
|
||||
.map(|()| buf.len())
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::Other, e)),
|
||||
CppStream::BufferedFile(inner) => unsafe { inner.as_mut().read_u8(pch, len) }
|
||||
.map(|()| buf.len())
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::Other, e)),
|
||||
CppStream::Hash(_) => Err(io::Error::new(
|
||||
io::ErrorKind::Unsupported,
|
||||
"Cannot read from CHashWriter",
|
||||
)),
|
||||
CppStream::Size(_) => Err(io::Error::new(
|
||||
io::ErrorKind::Unsupported,
|
||||
"Cannot read from CSizeComputer",
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> io::Write for CppStream<'a> {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
unsafe { self.inner.as_mut().write_u8(buf.as_ptr(), buf.len()) }
|
||||
.map(|()| buf.len())
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))
|
||||
let pch = buf.as_ptr();
|
||||
let len = buf.len();
|
||||
match self {
|
||||
CppStream::Data(inner) => unsafe { inner.as_mut().write_u8(pch, len) }
|
||||
.map(|()| buf.len())
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::Other, e)),
|
||||
CppStream::AutoFile(inner) => unsafe { inner.as_mut().write_u8(pch, len) }
|
||||
.map(|()| buf.len())
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::Other, e)),
|
||||
CppStream::BufferedFile(_) => Err(io::Error::new(
|
||||
io::ErrorKind::Unsupported,
|
||||
"Cannot write to CBufferedFile",
|
||||
)),
|
||||
CppStream::Hash(inner) => unsafe { inner.as_mut().write_u8(pch, len) }
|
||||
.map(|()| buf.len())
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::Other, e)),
|
||||
CppStream::Size(inner) => unsafe { inner.as_mut().write_u8(pch, len) }
|
||||
.map(|()| buf.len())
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::Other, e)),
|
||||
}
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
|
|
|
@ -1079,6 +1079,11 @@ protected:
|
|||
public:
|
||||
CSizeComputer(int nTypeIn, int nVersionIn) : nSize(0), nType(nTypeIn), nVersion(nVersionIn) {}
|
||||
|
||||
void write_u8(const unsigned char* pch, size_t nSize)
|
||||
{
|
||||
write(reinterpret_cast<const char*>(pch), nSize);
|
||||
}
|
||||
|
||||
void write(const char *psz, size_t _nSize)
|
||||
{
|
||||
this->nSize += _nSize;
|
||||
|
|
|
@ -509,6 +509,11 @@ public:
|
|||
int GetType() const { return nType; }
|
||||
int GetVersion() const { return nVersion; }
|
||||
|
||||
void read_u8(unsigned char* pch, size_t nSize)
|
||||
{
|
||||
read(reinterpret_cast<char*>(pch), nSize);
|
||||
}
|
||||
|
||||
void read(char* pch, size_t nSize)
|
||||
{
|
||||
if (!file)
|
||||
|
@ -530,6 +535,11 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void write_u8(const unsigned char* pch, size_t nSize)
|
||||
{
|
||||
write(reinterpret_cast<const char*>(pch), nSize);
|
||||
}
|
||||
|
||||
void write(const char* pch, size_t nSize)
|
||||
{
|
||||
if (!file)
|
||||
|
@ -631,6 +641,11 @@ public:
|
|||
return src == NULL || (nReadPos == nSrcPos && feof(src));
|
||||
}
|
||||
|
||||
void read_u8(unsigned char* pch, size_t nSize)
|
||||
{
|
||||
read(reinterpret_cast<char*>(pch), nSize);
|
||||
}
|
||||
|
||||
// read a number of bytes
|
||||
void read(char *pch, size_t nSize) {
|
||||
if (nSize == 0) return;
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright (c) 2023 The Zcash developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
||||
|
||||
#include "streams_rust.h"
|
||||
|
||||
rust::Box<stream::CppStream> ToRustStream(RustDataStream& stream) {
|
||||
return stream::from_data(stream);
|
||||
}
|
||||
|
||||
rust::Box<stream::CppStream> ToRustStream(CAutoFile& file) {
|
||||
return stream::from_auto_file(file);
|
||||
}
|
||||
|
||||
rust::Box<stream::CppStream> ToRustStream(CBufferedFile& file) {
|
||||
return stream::from_buffered_file(file);
|
||||
}
|
||||
|
||||
rust::Box<stream::CppStream> ToRustStream(CHashWriter& writer) {
|
||||
return stream::from_hash_writer(writer);
|
||||
}
|
||||
|
||||
rust::Box<stream::CppStream> ToRustStream(CSizeComputer& sc) {
|
||||
return stream::from_size_computer(sc);
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright (c) 2023 The Zcash developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
||||
|
||||
#ifndef ZCASH_STREAMS_RUST_H
|
||||
#define ZCASH_STREAMS_RUST_H
|
||||
|
||||
#include "hash.h"
|
||||
#include "serialize.h"
|
||||
#include "streams.h"
|
||||
|
||||
#include <rust/bridge.h>
|
||||
#include <rust/cxx.h>
|
||||
|
||||
rust::Box<stream::CppStream> ToRustStream(RustDataStream& stream);
|
||||
rust::Box<stream::CppStream> ToRustStream(CAutoFile& file);
|
||||
rust::Box<stream::CppStream> ToRustStream(CBufferedFile& file);
|
||||
rust::Box<stream::CppStream> ToRustStream(CHashWriter& writer);
|
||||
rust::Box<stream::CppStream> ToRustStream(CSizeComputer& sc);
|
||||
|
||||
#endif // ZCASH_STREAMS_RUST_H
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include "uint256.h"
|
||||
#include "serialize.h"
|
||||
#include "streams_rust.h"
|
||||
|
||||
#include "Zcash.h"
|
||||
#include "zcash/util.h"
|
||||
|
@ -296,7 +297,7 @@ public:
|
|||
template<typename Stream>
|
||||
void Serialize(Stream& s) const {
|
||||
try {
|
||||
inner->serialize(s);
|
||||
inner->serialize(*ToRustStream(s));
|
||||
} catch (const std::exception& e) {
|
||||
throw std::ios_base::failure(e.what());
|
||||
}
|
||||
|
@ -305,7 +306,7 @@ public:
|
|||
template<typename Stream>
|
||||
void Unserialize(Stream& s) {
|
||||
try {
|
||||
inner = merkle_frontier::parse_orchard(s);
|
||||
inner = merkle_frontier::parse_orchard(*ToRustStream(s));
|
||||
} catch (const std::exception& e) {
|
||||
throw std::ios_base::failure(e.what());
|
||||
}
|
||||
|
@ -341,7 +342,7 @@ public:
|
|||
template<typename Stream>
|
||||
void Serialize(Stream& s) const {
|
||||
try {
|
||||
frontier.inner->serialize_legacy(s);
|
||||
frontier.inner->serialize_legacy(*ToRustStream(s));
|
||||
} catch (const std::exception& e) {
|
||||
throw std::ios_base::failure(e.what());
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue