Skip to content

Commit

Permalink
Merge pull request #460 from Chia-Network/owned-conditions
Browse files Browse the repository at this point in the history
Move `PySpend` and `PySpendBundleConditions` to `chia-consensus` and rename to `Owned*`
  • Loading branch information
Rigidity authored Apr 15, 2024
2 parents 68b9d52 + 52598ea commit 0b4d49b
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 147 deletions.
1 change: 1 addition & 0 deletions crates/chia-consensus/src/gen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pub mod flags;
pub mod get_puzzle_and_solution;
pub mod messages;
pub mod opcodes;
pub mod owned_conditions;
pub mod run_block_generator;
pub mod run_puzzle;
pub mod sanitize_int;
Expand Down
143 changes: 143 additions & 0 deletions crates/chia-consensus/src/gen/owned_conditions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
use chia_protocol::{Bytes, Bytes32, Bytes48};
use chia_streamable_macro::Streamable;
use clvmr::{Allocator, NodePtr};

use super::conditions::{Spend, SpendBundleConditions};

#[cfg(feature = "py-bindings")]
use chia_py_streamable_macro::{PyJsonDict, PyStreamable};

#[derive(Streamable, Hash, Debug, Clone, Eq, PartialEq)]
#[cfg_attr(
feature = "py-bindings",
pyo3::pyclass(name = "Spend", get_all, frozen),
derive(PyJsonDict, PyStreamable)
)]
pub struct OwnedSpend {
pub coin_id: Bytes32,
pub parent_id: Bytes32,
pub puzzle_hash: Bytes32,
pub coin_amount: u64,
pub height_relative: Option<u32>,
pub seconds_relative: Option<u64>,
pub before_height_relative: Option<u32>,
pub before_seconds_relative: Option<u64>,
pub birth_height: Option<u32>,
pub birth_seconds: Option<u64>,
pub create_coin: Vec<(Bytes32, u64, Option<Bytes>)>,
pub agg_sig_me: Vec<(Bytes48, Bytes)>,
pub agg_sig_parent: Vec<(Bytes48, Bytes)>,
pub agg_sig_puzzle: Vec<(Bytes48, Bytes)>,
pub agg_sig_amount: Vec<(Bytes48, Bytes)>,
pub agg_sig_puzzle_amount: Vec<(Bytes48, Bytes)>,
pub agg_sig_parent_amount: Vec<(Bytes48, Bytes)>,
pub agg_sig_parent_puzzle: Vec<(Bytes48, Bytes)>,
pub flags: u32,
}

#[derive(Streamable, Hash, Debug, Clone, Eq, PartialEq)]
#[cfg_attr(
feature = "py-bindings",
pyo3::pyclass(name = "SpendBundleConditions", get_all, frozen),
derive(PyJsonDict, PyStreamable)
)]
pub struct OwnedSpendBundleConditions {
pub spends: Vec<OwnedSpend>,
pub reserve_fee: u64,
// the highest height/time conditions (i.e. most strict)
pub height_absolute: u32,
pub seconds_absolute: u64,
// when set, this is the lowest (i.e. most restrictive) of all
// ASSERT_BEFORE_HEIGHT_ABSOLUTE conditions
pub before_height_absolute: Option<u32>,
// ASSERT_BEFORE_SECONDS_ABSOLUTE conditions
pub before_seconds_absolute: Option<u64>,
// Unsafe Agg Sig conditions (i.e. not tied to the spend generating it)
pub agg_sig_unsafe: Vec<(Bytes48, Bytes)>,
pub cost: u64,
// the sum of all values of all spent coins
pub removal_amount: u128,
// the sum of all amounts of CREATE_COIN conditions
pub addition_amount: u128,
}

impl OwnedSpend {
pub fn from(a: &Allocator, spend: Spend) -> Self {
let mut create_coin =
Vec::<(Bytes32, u64, Option<Bytes>)>::with_capacity(spend.create_coin.len());
for c in spend.create_coin {
create_coin.push((
c.puzzle_hash,
c.amount,
if c.hint != a.nil() {
Some(a.atom(c.hint).as_ref().into())
} else {
None
},
));
}

Self {
coin_id: *spend.coin_id,
parent_id: a.atom(spend.parent_id).as_ref().try_into().unwrap(),
puzzle_hash: a.atom(spend.puzzle_hash).as_ref().try_into().unwrap(),
coin_amount: spend.coin_amount,
height_relative: spend.height_relative,
seconds_relative: spend.seconds_relative,
before_height_relative: spend.before_height_relative,
before_seconds_relative: spend.before_seconds_relative,
birth_height: spend.birth_height,
birth_seconds: spend.birth_seconds,
create_coin,
agg_sig_me: convert_agg_sigs(a, &spend.agg_sig_me),
agg_sig_parent: convert_agg_sigs(a, &spend.agg_sig_parent),
agg_sig_puzzle: convert_agg_sigs(a, &spend.agg_sig_puzzle),
agg_sig_amount: convert_agg_sigs(a, &spend.agg_sig_amount),
agg_sig_puzzle_amount: convert_agg_sigs(a, &spend.agg_sig_puzzle_amount),
agg_sig_parent_amount: convert_agg_sigs(a, &spend.agg_sig_parent_amount),
agg_sig_parent_puzzle: convert_agg_sigs(a, &spend.agg_sig_parent_puzzle),
flags: spend.flags,
}
}
}

impl OwnedSpendBundleConditions {
pub fn from(a: &Allocator, sb: SpendBundleConditions) -> Self {
let mut spends = Vec::<OwnedSpend>::new();
for s in sb.spends {
spends.push(OwnedSpend::from(a, s));
}

let mut agg_sigs = Vec::<(Bytes48, Bytes)>::with_capacity(sb.agg_sig_unsafe.len());
for (pk, msg) in sb.agg_sig_unsafe {
agg_sigs.push((
a.atom(pk).as_ref().try_into().unwrap(),
a.atom(msg).as_ref().into(),
));
}

Self {
spends,
reserve_fee: sb.reserve_fee,
height_absolute: sb.height_absolute,
seconds_absolute: sb.seconds_absolute,
before_height_absolute: sb.before_height_absolute,
before_seconds_absolute: sb.before_seconds_absolute,
agg_sig_unsafe: agg_sigs,
cost: sb.cost,
removal_amount: sb.removal_amount,
addition_amount: sb.addition_amount,
}
}
}

fn convert_agg_sigs(a: &Allocator, agg_sigs: &[(NodePtr, NodePtr)]) -> Vec<(Bytes48, Bytes)> {
let mut ret = Vec::<(Bytes48, Bytes)>::new();
for (pk, msg) in agg_sigs {
ret.push((
a.atom(*pk).as_ref().try_into().unwrap(),
a.atom(*msg).as_ref().into(),
));
}
ret
}
14 changes: 6 additions & 8 deletions wheel/src/api.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
use crate::run_generator::{
convert_spend_bundle_conds, run_block_generator, run_block_generator2, PySpend,
PySpendBundleConditions,
};
use crate::run_generator::{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 All @@ -10,6 +7,7 @@ use chia_consensus::gen::flags::{
ENABLE_SOFTFORK_CONDITION, MEMPOOL_MODE, NO_RELATIVE_CONDITIONS_ON_EPHEMERAL, NO_UNKNOWN_CONDS,
STRICT_ARGS_COUNT,
};
use chia_consensus::gen::owned_conditions::{OwnedSpend, OwnedSpendBundleConditions};
use chia_consensus::gen::run_puzzle::run_puzzle as native_run_puzzle;
use chia_consensus::gen::solution_generator::solution_generator as native_solution_generator;
use chia_consensus::gen::solution_generator::solution_generator_backrefs as native_solution_generator_backrefs;
Expand Down Expand Up @@ -157,12 +155,12 @@ fn run_puzzle(
amount: u64,
max_cost: Cost,
flags: u32,
) -> PyResult<PySpendBundleConditions> {
) -> PyResult<OwnedSpendBundleConditions> {
let mut a = make_allocator(LIMIT_HEAP);
let conds = native_run_puzzle::<MempoolVisitor>(
&mut a, puzzle, solution, parent_id, amount, max_cost, flags,
)?;
Ok(convert_spend_bundle_conds(&a, conds))
Ok(OwnedSpendBundleConditions::from(&a, conds))
}

// this is like a CoinSpend but with references to the puzzle and solution,
Expand Down Expand Up @@ -337,7 +335,7 @@ pub fn chia_rs(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_function(wrap_pyfunction!(solution_generator_backrefs, m)?)?;
m.add_function(wrap_pyfunction!(supports_fast_forward, m)?)?;
m.add_function(wrap_pyfunction!(fast_forward_singleton, m)?)?;
m.add_class::<PySpendBundleConditions>()?;
m.add_class::<OwnedSpendBundleConditions>()?;
m.add(
"ELIGIBLE_FOR_DEDUP",
chia_consensus::gen::conditions::ELIGIBLE_FOR_DEDUP,
Expand All @@ -346,7 +344,7 @@ pub fn chia_rs(_py: Python, m: &PyModule) -> PyResult<()> {
"ELIGIBLE_FOR_FF",
chia_consensus::gen::conditions::ELIGIBLE_FOR_FF,
)?;
m.add_class::<PySpend>()?;
m.add_class::<OwnedSpend>()?;

// constants
m.add_class::<ConsensusConstants>()?;
Expand Down
151 changes: 12 additions & 139 deletions wheel/src/run_generator.rs
Original file line number Diff line number Diff line change
@@ -1,158 +1,25 @@
use chia_consensus::allocator::make_allocator;
use chia_consensus::gen::conditions::{EmptyVisitor, MempoolVisitor, Spend, SpendBundleConditions};
use chia_consensus::gen::conditions::{EmptyVisitor, MempoolVisitor};
use chia_consensus::gen::flags::ANALYZE_SPENDS;
use chia_consensus::gen::owned_conditions::OwnedSpendBundleConditions;
use chia_consensus::gen::run_block_generator::run_block_generator as native_run_block_generator;
use chia_consensus::gen::run_block_generator::run_block_generator2 as native_run_block_generator2;
use chia_consensus::gen::validation_error::ValidationErr;
use chia_protocol::bytes::{Bytes, Bytes32, Bytes48};

use clvmr::allocator::{Allocator, NodePtr};
use clvmr::cost::Cost;

use pyo3::buffer::PyBuffer;
use pyo3::prelude::*;
use pyo3::types::PyList;

use chia_py_streamable_macro::{PyJsonDict, PyStreamable};
use chia_streamable_macro::Streamable;

#[cfg(feature = "py-bindings")]
use chia_traits::{FromJsonDict, ToJsonDict};

#[pyclass(name = "Spend", get_all, frozen)]
#[derive(Streamable, PyJsonDict, PyStreamable, Hash, Debug, Clone, Eq, PartialEq)]
pub struct PySpend {
pub coin_id: Bytes32,
pub parent_id: Bytes32,
pub puzzle_hash: Bytes32,
pub coin_amount: u64,
pub height_relative: Option<u32>,
pub seconds_relative: Option<u64>,
pub before_height_relative: Option<u32>,
pub before_seconds_relative: Option<u64>,
pub birth_height: Option<u32>,
pub birth_seconds: Option<u64>,
pub create_coin: Vec<(Bytes32, u64, Option<Bytes>)>,
pub agg_sig_me: Vec<(Bytes48, Bytes)>,
pub agg_sig_parent: Vec<(Bytes48, Bytes)>,
pub agg_sig_puzzle: Vec<(Bytes48, Bytes)>,
pub agg_sig_amount: Vec<(Bytes48, Bytes)>,
pub agg_sig_puzzle_amount: Vec<(Bytes48, Bytes)>,
pub agg_sig_parent_amount: Vec<(Bytes48, Bytes)>,
pub agg_sig_parent_puzzle: Vec<(Bytes48, Bytes)>,
pub flags: u32,
}

#[pyclass(name = "SpendBundleConditions", get_all, frozen)]
#[derive(Streamable, PyJsonDict, PyStreamable, Hash, Debug, Clone, Eq, PartialEq)]
pub struct PySpendBundleConditions {
pub spends: Vec<PySpend>,
pub reserve_fee: u64,
// the highest height/time conditions (i.e. most strict)
pub height_absolute: u32,
pub seconds_absolute: u64,
// when set, this is the lowest (i.e. most restrictive) of all
// ASSERT_BEFORE_HEIGHT_ABSOLUTE conditions
pub before_height_absolute: Option<u32>,
// ASSERT_BEFORE_SECONDS_ABSOLUTE conditions
pub before_seconds_absolute: Option<u64>,
// Unsafe Agg Sig conditions (i.e. not tied to the spend generating it)
pub agg_sig_unsafe: Vec<(Bytes48, Bytes)>,
pub cost: u64,
// the sum of all values of all spent coins
pub removal_amount: u128,
// the sum of all amounts of CREATE_COIN conditions
pub addition_amount: u128,
}

fn convert_agg_sigs(a: &Allocator, agg_sigs: &[(NodePtr, NodePtr)]) -> Vec<(Bytes48, Bytes)> {
let mut ret = Vec::<(Bytes48, Bytes)>::new();
for (pk, msg) in agg_sigs {
ret.push((
a.atom(*pk).as_ref().try_into().unwrap(),
a.atom(*msg).as_ref().into(),
));
}
ret
}

fn convert_spend(a: &Allocator, spend: Spend) -> PySpend {
let mut create_coin =
Vec::<(Bytes32, u64, Option<Bytes>)>::with_capacity(spend.create_coin.len());
for c in spend.create_coin {
create_coin.push((
c.puzzle_hash,
c.amount,
if c.hint != a.nil() {
Some(a.atom(c.hint).as_ref().into())
} else {
None
},
));
}

PySpend {
coin_id: *spend.coin_id,
parent_id: a.atom(spend.parent_id).as_ref().try_into().unwrap(),
puzzle_hash: a.atom(spend.puzzle_hash).as_ref().try_into().unwrap(),
coin_amount: spend.coin_amount,
height_relative: spend.height_relative,
seconds_relative: spend.seconds_relative,
before_height_relative: spend.before_height_relative,
before_seconds_relative: spend.before_seconds_relative,
birth_height: spend.birth_height,
birth_seconds: spend.birth_seconds,
create_coin,
agg_sig_me: convert_agg_sigs(a, &spend.agg_sig_me),
agg_sig_parent: convert_agg_sigs(a, &spend.agg_sig_parent),
agg_sig_puzzle: convert_agg_sigs(a, &spend.agg_sig_puzzle),
agg_sig_amount: convert_agg_sigs(a, &spend.agg_sig_amount),
agg_sig_puzzle_amount: convert_agg_sigs(a, &spend.agg_sig_puzzle_amount),
agg_sig_parent_amount: convert_agg_sigs(a, &spend.agg_sig_parent_amount),
agg_sig_parent_puzzle: convert_agg_sigs(a, &spend.agg_sig_parent_puzzle),
flags: spend.flags,
}
}

pub fn convert_spend_bundle_conds(
a: &Allocator,
sb: SpendBundleConditions,
) -> PySpendBundleConditions {
let mut spends = Vec::<PySpend>::new();
for s in sb.spends {
spends.push(convert_spend(a, s));
}

let mut agg_sigs = Vec::<(Bytes48, Bytes)>::with_capacity(sb.agg_sig_unsafe.len());
for (pk, msg) in sb.agg_sig_unsafe {
agg_sigs.push((
a.atom(pk).as_ref().try_into().unwrap(),
a.atom(msg).as_ref().into(),
));
}

PySpendBundleConditions {
spends,
reserve_fee: sb.reserve_fee,
height_absolute: sb.height_absolute,
seconds_absolute: sb.seconds_absolute,
before_height_absolute: sb.before_height_absolute,
before_seconds_absolute: sb.before_seconds_absolute,
agg_sig_unsafe: agg_sigs,
cost: sb.cost,
removal_amount: sb.removal_amount,
addition_amount: sb.addition_amount,
}
}

#[pyfunction]
pub fn run_block_generator(
_py: Python,
program: PyBuffer<u8>,
block_refs: &PyList,
max_cost: Cost,
flags: u32,
) -> PyResult<(Option<u32>, Option<PySpendBundleConditions>)> {
) -> PyResult<(Option<u32>, Option<OwnedSpendBundleConditions>)> {
let mut allocator = make_allocator(flags);

let mut refs = Vec::<&[u8]>::new();
Expand Down Expand Up @@ -185,7 +52,10 @@ pub fn run_block_generator(
// everything was successful
(
None,
Some(convert_spend_bundle_conds(&allocator, spend_bundle_conds)),
Some(OwnedSpendBundleConditions::from(
&allocator,
spend_bundle_conds,
)),
)
}
Err(ValidationErr(_, error_code)) => {
Expand All @@ -203,7 +73,7 @@ pub fn run_block_generator2(
block_refs: &PyList,
max_cost: Cost,
flags: u32,
) -> PyResult<(Option<u32>, Option<PySpendBundleConditions>)> {
) -> PyResult<(Option<u32>, Option<OwnedSpendBundleConditions>)> {
let mut allocator = make_allocator(flags);

let mut refs = Vec::<&[u8]>::new();
Expand Down Expand Up @@ -236,7 +106,10 @@ pub fn run_block_generator2(
// everything was successful
(
None,
Some(convert_spend_bundle_conds(&allocator, spend_bundle_conds)),
Some(OwnedSpendBundleConditions::from(
&allocator,
spend_bundle_conds,
)),
)
}
Err(ValidationErr(_, error_code)) => {
Expand Down

0 comments on commit 0b4d49b

Please sign in to comment.