Skip to content

Commit

Permalink
Merge pull request #632 from Chia-Network/setup_generator_args
Browse files Browse the repository at this point in the history
refactors
  • Loading branch information
arvidn committed Jul 31, 2024
2 parents c906a85 + f6c1982 commit ce4fff3
Show file tree
Hide file tree
Showing 11 changed files with 145 additions and 168 deletions.
4 changes: 2 additions & 2 deletions crates/chia-consensus/benches/run-generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ fn run(c: &mut Criterion) {
let mut a = Allocator::new();
let start = Instant::now();

let conds = run_block_generator::<_, MempoolVisitor>(
let conds = run_block_generator::<_, MempoolVisitor, _>(
&mut a,
gen,
&block_refs,
Expand All @@ -69,7 +69,7 @@ fn run(c: &mut Criterion) {
let mut a = Allocator::new();
let start = Instant::now();

let conds = run_block_generator2::<_, MempoolVisitor>(
let conds = run_block_generator2::<_, MempoolVisitor, _>(
&mut a,
gen,
&block_refs,
Expand Down
8 changes: 4 additions & 4 deletions crates/chia-consensus/fuzz/fuzz_targets/run-generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,21 @@ use libfuzzer_sys::fuzz_target;

fuzz_target!(|data: &[u8]| {
let mut a1 = make_allocator(LIMIT_HEAP);
let r1 = run_block_generator::<&[u8], MempoolVisitor>(
let r1 = run_block_generator::<&[u8], MempoolVisitor, _>(
&mut a1,
data,
&[],
[],
110_000_000,
ALLOW_BACKREFS,
&TEST_CONSTANTS,
);
drop(a1);

let mut a2 = make_allocator(LIMIT_HEAP);
let r2 = run_block_generator2::<&[u8], MempoolVisitor>(
let r2 = run_block_generator2::<&[u8], MempoolVisitor, _>(
&mut a2,
data,
&[],
[],
110_000_000,
ALLOW_BACKREFS,
&TEST_CONSTANTS,
Expand Down
62 changes: 41 additions & 21 deletions crates/chia-consensus/src/gen/run_block_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,31 @@ fn subtract_cost(a: &Allocator, cost_left: &mut Cost, subtract: Cost) -> Result<
}
}

/// Prepares the arguments passed to the block generator. They are in the form:
/// (DESERIALIZER_MOD (block1 block2 block3 ...))
pub fn setup_generator_args<GenBuf: AsRef<[u8]>, I: IntoIterator<Item = GenBuf>>(
a: &mut Allocator,
block_refs: I,
) -> Result<NodePtr, ValidationErr>
where
<I as IntoIterator>::IntoIter: DoubleEndedIterator,
{
let clvm_deserializer = node_from_bytes(a, &CLVM_DESERIALIZER)?;

// iterate in reverse order since we're building a linked list from
// the tail
let mut blocks = NodePtr::NIL;
for g in block_refs.into_iter().rev() {
let ref_gen = a.new_atom(g.as_ref())?;
blocks = a.new_pair(ref_gen, blocks)?;
}

// the first argument to the generator is the serializer, followed by a list
// of the blocks it requested.
let args = a.new_pair(blocks, NodePtr::NIL)?;
Ok(a.new_pair(clvm_deserializer, args)?)
}

// Runs the generator ROM and passes in the program (transactions generator).
// The program is expected to return a list of spends. Each item being:

Expand All @@ -38,14 +63,17 @@ fn subtract_cost(a: &Allocator, cost_left: &mut Cost, subtract: Cost) -> Result<
// the only reason we need to pass in the allocator is because the returned
// SpendBundleConditions contains NodePtr fields. If that's changed, we could
// create the allocator inside this functions as well.
pub fn run_block_generator<GenBuf: AsRef<[u8]>, V: SpendVisitor>(
pub fn run_block_generator<GenBuf: AsRef<[u8]>, V: SpendVisitor, I: IntoIterator<Item = GenBuf>>(
a: &mut Allocator,
program: &[u8],
block_refs: &[GenBuf],
block_refs: I,
max_cost: u64,
flags: u32,
constants: &ConsensusConstants,
) -> Result<SpendBundleConditions, ValidationErr> {
) -> Result<SpendBundleConditions, ValidationErr>
where
<I as IntoIterator>::IntoIter: DoubleEndedIterator,
{
let mut cost_left = max_cost;
let byte_cost = program.len() as u64 * constants.cost_per_byte;

Expand All @@ -58,10 +86,12 @@ pub fn run_block_generator<GenBuf: AsRef<[u8]>, V: SpendVisitor>(
node_from_bytes(a, program)?
};

// this is setting up the arguments to be passed to the generator ROM,
// not the actual generator (the ROM does that).
// iterate in reverse order since we're building a linked list from
// the tail
let mut args = a.nil();
for g in block_refs.iter().rev() {
for g in block_refs.into_iter().rev() {
let ref_gen = a.new_atom(g.as_ref())?;
args = a.new_pair(ref_gen, args)?;
}
Expand Down Expand Up @@ -112,39 +142,29 @@ pub fn extract_n<const N: usize>(
// you only pay cost for the generator, the puzzles and the conditions).
// it also does not apply the stack depth or object allocation limits the same,
// as each puzzle run in its own environment.
pub fn run_block_generator2<GenBuf: AsRef<[u8]>, V: SpendVisitor>(
pub fn run_block_generator2<GenBuf: AsRef<[u8]>, V: SpendVisitor, I: IntoIterator<Item = GenBuf>>(
a: &mut Allocator,
program: &[u8],
block_refs: &[GenBuf],
block_refs: I,
max_cost: u64,
flags: u32,
constants: &ConsensusConstants,
) -> Result<SpendBundleConditions, ValidationErr> {
) -> Result<SpendBundleConditions, ValidationErr>
where
<I as IntoIterator>::IntoIter: DoubleEndedIterator,
{
let byte_cost = program.len() as u64 * constants.cost_per_byte;

let mut cost_left = max_cost;
subtract_cost(a, &mut cost_left, byte_cost)?;

let clvm_deserializer = node_from_bytes(a, &CLVM_DESERIALIZER)?;
let (program, backrefs) = if (flags & ALLOW_BACKREFS) != 0 {
node_from_bytes_backrefs_record(a, program)?
} else {
(node_from_bytes(a, program)?, HashSet::<NodePtr>::new())
};

// iterate in reverse order since we're building a linked list from
// the tail
let mut blocks = a.nil();
for g in block_refs.iter().rev() {
let ref_gen = a.new_atom(g.as_ref())?;
blocks = a.new_pair(ref_gen, blocks)?;
}

// the first argument to the generator is the serializer, followed by a list
// of the blocks it requested.
let mut args = a.new_pair(blocks, a.nil())?;
args = a.new_pair(clvm_deserializer, args)?;

let args = setup_generator_args(a, block_refs)?;
let dialect = ChiaDialect::new(flags);

let Reduction(clvm_cost, mut all_spends) = run_program(a, &dialect, program, args, cost_left)?;
Expand Down
4 changes: 2 additions & 2 deletions crates/chia-consensus/src/gen/test_generators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ fn run_generator(#[case] name: &str) {
for (flags, expected) in zip(&[DEFAULT_FLAGS, DEFAULT_FLAGS | MEMPOOL_MODE], expected) {
println!("flags: {flags:x}");
let mut a = make_allocator(*flags);
let conds = run_block_generator::<_, MempoolVisitor>(
let conds = run_block_generator::<_, MempoolVisitor, _>(
&mut a,
&generator,
&block_refs,
Expand All @@ -246,7 +246,7 @@ fn run_generator(#[case] name: &str) {
};

let mut a = make_allocator(*flags);
let conds = run_block_generator2::<_, MempoolVisitor>(
let conds = run_block_generator2::<_, MempoolVisitor, _>(
&mut a,
&generator,
&block_refs,
Expand Down
4 changes: 2 additions & 2 deletions crates/chia-tools/src/bin/analyze-chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ fn main() {
// after the hard fork, we run blocks without paying for the
// CLVM generator ROM
let block_runner = if height >= 5_496_000 {
run_block_generator2::<_, EmptyVisitor>
run_block_generator2::<_, EmptyVisitor, _>
} else {
run_block_generator::<_, EmptyVisitor>
run_block_generator::<_, EmptyVisitor, _>
};

let generator = block
Expand Down
6 changes: 3 additions & 3 deletions crates/chia-tools/src/bin/test-block-generators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,9 +159,9 @@ fn main() {
// after the hard fork, we run blocks without paying for the
// CLVM generator ROM
let block_runner = if height >= 5_496_000 {
run_block_generator2::<_, EmptyVisitor>
run_block_generator2::<_, EmptyVisitor, _>
} else {
run_block_generator::<_, EmptyVisitor>
run_block_generator::<_, EmptyVisitor, _>
};

let mut conditions =
Expand All @@ -181,7 +181,7 @@ fn main() {
}

if args.validate {
let mut baseline = run_block_generator::<_, EmptyVisitor>(
let mut baseline = run_block_generator::<_, EmptyVisitor, _>(
&mut a,
generator.as_ref(),
&block_refs,
Expand Down
11 changes: 0 additions & 11 deletions wheel/src/adapt_response.rs

This file was deleted.

56 changes: 24 additions & 32 deletions wheel/src/api.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::run_generator::{run_block_generator, run_block_generator2};
use crate::run_generator::{py_to_slice, run_block_generator, run_block_generator2};
use chia_consensus::allocator::make_allocator;
use chia_consensus::consensus_constants::ConsensusConstants;
use chia_consensus::gen::conditions::MempoolVisitor;
Expand Down Expand Up @@ -52,7 +52,6 @@ use std::iter::zip;

use crate::run_program::{run_chia_program, serialized_length};

use crate::adapt_response::eval_err_to_pyresult;
use chia_consensus::fast_forward::fast_forward_singleton as native_ff;
use chia_consensus::gen::get_puzzle_and_solution::get_puzzle_and_solution_for_coin as parse_puzzle_solution;
use chia_consensus::gen::validation_error::ValidationErr;
Expand Down Expand Up @@ -107,20 +106,15 @@ pub fn confirm_not_included_already_hashed(
}

#[pyfunction]
pub fn tree_hash(py: Python<'_>, blob: PyBuffer<u8>) -> PyResult<Bound<'_, PyBytes>> {
assert!(
blob.is_c_contiguous(),
"tree_hash() must be called with a contiguous buffer"
);
let slice =
unsafe { std::slice::from_raw_parts(blob.buf_ptr() as *const u8, blob.len_bytes()) };
pub fn tree_hash<'a>(py: Python<'a>, blob: PyBuffer<u8>) -> PyResult<Bound<'_, PyBytes>> {
let slice = py_to_slice::<'a>(blob);
Ok(PyBytes::new_bound(py, &tree_hash_from_bytes(slice)?))
}

#[allow(clippy::too_many_arguments)]
#[pyfunction]
pub fn get_puzzle_and_solution_for_coin(
py: Python<'_>,
pub fn get_puzzle_and_solution_for_coin<'a>(
py: Python<'a>,
program: PyBuffer<u8>,
args: PyBuffer<u8>,
max_cost: Cost,
Expand All @@ -131,12 +125,8 @@ pub fn get_puzzle_and_solution_for_coin(
) -> PyResult<(Bound<'_, PyBytes>, Bound<'_, PyBytes>)> {
let mut allocator = make_allocator(LIMIT_HEAP);

assert!(program.is_c_contiguous(), "program must be contiguous");
let program =
unsafe { std::slice::from_raw_parts(program.buf_ptr() as *const u8, program.len_bytes()) };

assert!(args.is_c_contiguous(), "args must be contiguous");
let args = unsafe { std::slice::from_raw_parts(args.buf_ptr() as *const u8, args.len_bytes()) };
let program = py_to_slice::<'a>(program);
let args = py_to_slice::<'a>(args);

let deserialize = if (flags & ALLOW_BACKREFS) != 0 {
node_from_bytes_backrefs
Expand All @@ -147,14 +137,19 @@ pub fn get_puzzle_and_solution_for_coin(
let args = deserialize(&mut allocator, args)?;
let dialect = &ChiaDialect::new(flags);

let r = py.allow_threads(|| -> Result<(NodePtr, NodePtr), EvalErr> {
let Reduction(_cost, result) =
run_program(&mut allocator, dialect, program, args, max_cost)?;
match parse_puzzle_solution(&allocator, result, find_parent, find_amount, find_ph) {
Err(ValidationErr(n, _)) => Err(EvalErr(n, "coin not found".to_string())),
Ok(pair) => Ok(pair),
}
});
let (puzzle, solution) = py
.allow_threads(|| -> Result<(NodePtr, NodePtr), EvalErr> {
let Reduction(_cost, result) =
run_program(&mut allocator, dialect, program, args, max_cost)?;
match parse_puzzle_solution(&allocator, result, find_parent, find_amount, find_ph) {
Err(ValidationErr(n, _)) => Err(EvalErr(n, "coin not found".to_string())),
Ok(pair) => Ok(pair),
}
})
.map_err(|e| {
let blob = node_to_bytes(&allocator, e.0).ok().map(hex::encode);
PyValueError::new_err((e.1, blob))
})?;

// keep serializing normally, until wallets support backrefs
let serialize = node_to_bytes;
Expand All @@ -165,13 +160,10 @@ pub fn get_puzzle_and_solution_for_coin(
node_to_bytes
};
*/
match r {
Err(eval_err) => eval_err_to_pyresult(eval_err, &allocator),
Ok((puzzle, solution)) => Ok((
PyBytes::new_bound(py, &serialize(&allocator, puzzle)?),
PyBytes::new_bound(py, &serialize(&allocator, solution)?),
)),
}
Ok((
PyBytes::new_bound(py, &serialize(&allocator, puzzle)?),
PyBytes::new_bound(py, &serialize(&allocator, solution)?),
))
}

#[pyfunction]
Expand Down
1 change: 0 additions & 1 deletion wheel/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#![allow(unsafe_code, clippy::needless_pass_by_value)]

mod adapt_response;
mod api;
mod run_generator;
mod run_program;
Loading

0 comments on commit ce4fff3

Please sign in to comment.