Skip to content

Commit 6814e4d

Browse files
authored
Add support for loading Rue files (#325)
* Add support for loading Rue files * Make debug dialect work * Always enable debug dialect in simulator * Fix debug * De-specialize the simulator dialect * Add compile_chialisp and compile_rue split
1 parent 4091393 commit 6814e4d

File tree

17 files changed

+718
-101
lines changed

17 files changed

+718
-101
lines changed

Cargo.lock

Lines changed: 359 additions & 33 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,9 @@ console_error_panic_hook = "0.1.7"
174174
prettytable-rs = "0.10.0"
175175
clap = "4.5.50"
176176
bincode = "2.0.1"
177+
rue-compiler = "0.6.0"
178+
rue-options = "0.6.0"
179+
rue-lir = "0.6.0"
177180

178181
[profile.release]
179182
lto = true

crates/chia-sdk-bindings/src/program.rs

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use chia_puzzle_types::{
77
offer::{NotarizedPayment as ChiaNotarizedPayment, Payment as ChiaPayment},
88
};
99
use chia_sdk_driver::{OptionMetadata, RewardDistributor as SdkRewardDistributor, SpendContext};
10+
use chia_sdk_types::run_puzzle_with_cost;
1011
use chialisp::classic::clvm_tools::stages::run;
1112
use chialisp::classic::clvm_tools::stages::stage_0::TRunProgram;
1213
use chialisp::classic::clvm_tools::{
@@ -15,7 +16,7 @@ use chialisp::classic::clvm_tools::{
1516
use clvm_traits::{ClvmDecoder, ClvmEncoder, FromClvm};
1617
use clvm_utils::{TreeHash, tree_hash};
1718
use clvmr::{
18-
ChiaDialect, MEMPOOL_MODE, NodePtr, SExp, run_program,
19+
NodePtr, SExp,
1920
serde::{node_to_bytes, node_to_bytes_backrefs},
2021
};
2122
use num_bigint::BigInt;
@@ -59,21 +60,9 @@ impl Program {
5960
}
6061

6162
pub fn run(&self, solution: Self, max_cost: u64, mempool_mode: bool) -> Result<Output> {
62-
let mut flags = 0;
63-
64-
if mempool_mode {
65-
flags |= MEMPOOL_MODE;
66-
}
67-
6863
let mut ctx = self.0.lock().unwrap();
6964

70-
let reduction = run_program(
71-
&mut ctx,
72-
&ChiaDialect::new(flags),
73-
self.1,
74-
solution.1,
75-
max_cost,
76-
)?;
65+
let reduction = run_puzzle_with_cost(&mut ctx, self.1, solution.1, max_cost, mempool_mode)?;
7766

7867
Ok(Output {
7968
value: Program(self.0.clone(), reduction.1),

crates/chia-sdk-driver/src/spend_bundle_cost.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ pub fn spend_bundle_cost(coin_spends: &[CoinSpend]) -> Result<u64, DriverError>
1515
for coin_spend in coin_spends {
1616
let puzzle = coin_spend.puzzle_reveal.to_clvm(&mut allocator)?;
1717
let solution = coin_spend.solution.to_clvm(&mut allocator)?;
18-
let output = run_puzzle_with_cost(&mut allocator, puzzle, solution)?;
18+
let output = run_puzzle_with_cost(&mut allocator, puzzle, solution, 11_000_000_000, false)?;
1919
let conditions = Vec::<Condition>::from_clvm(&allocator, output.1)?;
2020

2121
cost += output.0;

crates/chia-sdk-signer/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ clvmr = { workspace = true }
2525
thiserror = { workspace = true }
2626
chia-sdk-types = { workspace = true }
2727
k256 = { workspace = true }
28+
rue-lir = { workspace = true }
2829

2930
[dev-dependencies]
3031
chia-puzzle-types = { workspace = true }

crates/chia-sdk-signer/src/required_signature.rs

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
use chia_protocol::CoinSpend;
2-
use chia_sdk_types::Condition;
2+
use chia_sdk_types::{Condition, is_debug_dialect_enabled};
33
use clvm_traits::{FromClvm, ToClvm};
4-
use clvmr::{Allocator, ChiaDialect, run_program};
4+
use clvmr::{
5+
Allocator, ChiaDialect, ENABLE_KECCAK_OPS_OUTSIDE_GUARD, dialect::Dialect, run_program,
6+
};
7+
use rue_lir::DebugDialect;
58

69
use crate::{
710
AggSigConstants, RequiredBlsSignature, RequiredSecpSignature, SecpDialect, SignerError,
@@ -21,10 +24,33 @@ impl RequiredSignature {
2124
allocator: &mut Allocator,
2225
coin_spend: &CoinSpend,
2326
constants: &AggSigConstants,
27+
) -> Result<Vec<Self>, SignerError> {
28+
if is_debug_dialect_enabled() {
29+
Self::from_coin_spend_with_dialect(
30+
allocator,
31+
coin_spend,
32+
constants,
33+
DebugDialect::new(ENABLE_KECCAK_OPS_OUTSIDE_GUARD, false),
34+
)
35+
} else {
36+
Self::from_coin_spend_with_dialect(
37+
allocator,
38+
coin_spend,
39+
constants,
40+
ChiaDialect::new(0),
41+
)
42+
}
43+
}
44+
45+
fn from_coin_spend_with_dialect<D: Dialect>(
46+
allocator: &mut Allocator,
47+
coin_spend: &CoinSpend,
48+
constants: &AggSigConstants,
49+
dialect: D,
2450
) -> Result<Vec<Self>, SignerError> {
2551
let puzzle = coin_spend.puzzle_reveal.to_clvm(allocator)?;
2652
let solution = coin_spend.solution.to_clvm(allocator)?;
27-
let dialect = SecpDialect::new(ChiaDialect::new(0));
53+
let dialect = SecpDialect::new(dialect);
2854
let output = run_program(allocator, &dialect, puzzle, solution, 11_000_000_000)?.1;
2955
let conditions = Vec::<Condition>::from_clvm(allocator, output)?;
3056

crates/chia-sdk-test/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ futures-util = { workspace = true, optional = true }
6666
prettytable-rs = {workspace = true }
6767
serde = { workspace = true, features = ["derive"], optional = true }
6868
bincode = { workspace = true, features = ["serde"], optional = true }
69+
rue-lir = { workspace = true }
6970

7071
[package.metadata.cargo-machete]
7172
ignored = ["prettytable-rs"]

crates/chia-sdk-test/src/announcements.rs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ use chia_sdk_types::{
55
AssertCoinAnnouncement, AssertPuzzleAnnouncement, CreateCoinAnnouncement,
66
CreatePuzzleAnnouncement,
77
},
8+
run_puzzle,
89
};
910
use clvm_traits::{FromClvm, ToClvm};
10-
use clvmr::{Allocator, ChiaDialect, NodePtr, reduction::Reduction, run_program};
11+
use clvmr::{Allocator, NodePtr};
1112

1213
#[derive(Debug, Default, Clone)]
1314
pub struct Announcements {
@@ -120,13 +121,7 @@ pub fn announcements_for_spend(coin_spend: &CoinSpend) -> anyhow::Result<Announc
120121
let puzzle = coin_spend.puzzle_reveal.to_clvm(allocator)?;
121122
let solution = coin_spend.solution.to_clvm(allocator)?;
122123

123-
let Reduction(_cost, output) = run_program(
124-
allocator,
125-
&ChiaDialect::new(0),
126-
puzzle,
127-
solution,
128-
11_000_000_000,
129-
)?;
124+
let output = run_puzzle(allocator, puzzle, solution)?;
130125

131126
let conditions = Vec::<NodePtr>::from_clvm(allocator, output)?;
132127

crates/chia-sdk-test/src/simulator.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use chia_bls::SecretKey;
44
use chia_consensus::validation_error::ErrorCode;
55
use chia_protocol::{Bytes32, Coin, CoinSpend, CoinState, Program, SpendBundle};
66
use chia_sdk_types::TESTNET11_CONSTANTS;
7+
use clvmr::ENABLE_KECCAK_OPS_OUTSIDE_GUARD;
78
use indexmap::{IndexMap, IndexSet, indexset};
89
use rand::{Rng, SeedableRng};
910
use rand_chacha::ChaCha8Rng;
@@ -189,9 +190,13 @@ impl Simulator {
189190
return Err(SimulatorError::Validation(ErrorCode::InvalidSpendBundle));
190191
}
191192

192-
let conds =
193-
validate_clvm_and_signature(&spend_bundle, 11_000_000_000 / 2, &TESTNET11_CONSTANTS, 0)
194-
.map_err(SimulatorError::Validation)?;
193+
let conds = validate_clvm_and_signature(
194+
&spend_bundle,
195+
11_000_000_000 / 2,
196+
&TESTNET11_CONSTANTS,
197+
ENABLE_KECCAK_OPS_OUTSIDE_GUARD,
198+
)
199+
.map_err(SimulatorError::Validation)?;
195200

196201
let puzzle_hashes: HashSet<Bytes32> =
197202
conds.spends.iter().map(|spend| spend.puzzle_hash).collect();

crates/chia-sdk-test/src/validate_clvm_and_signature.rs

Lines changed: 82 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,23 @@
1-
use chia_bls::{aggregate_verify_gt, hash_to_g2};
1+
use chia_bls::{PublicKey, aggregate_verify_gt, hash_to_g2};
22
use chia_consensus::{
3-
allocator::make_allocator, consensus_constants::ConsensusConstants,
4-
owned_conditions::OwnedSpendBundleConditions, spendbundle_conditions::run_spendbundle,
5-
validation_error::ErrorCode,
3+
allocator::make_allocator,
4+
conditions::{
5+
ELIGIBLE_FOR_DEDUP, MempoolVisitor, ParseState, SpendBundleConditions,
6+
process_single_spend, validate_conditions,
7+
},
8+
consensus_constants::ConsensusConstants,
9+
flags::COMPUTE_FINGERPRINT,
10+
owned_conditions::OwnedSpendBundleConditions,
11+
puzzle_fingerprint::compute_puzzle_fingerprint,
12+
run_block_generator::subtract_cost,
13+
solution_generator::calculate_generator_length,
14+
validation_error::{ErrorCode, ValidationErr},
615
};
7-
use chia_protocol::SpendBundle;
16+
use chia_protocol::{Bytes, SpendBundle};
17+
use chia_sdk_types::run_puzzle_with_cost;
818
use chia_sha2::Sha256;
9-
use clvmr::LIMIT_HEAP;
19+
use clvm_utils::tree_hash;
20+
use clvmr::{Allocator, LIMIT_HEAP, reduction::Reduction, serde::node_from_bytes};
1021

1122
// TODO: This function is copied here because WASM doesn't support std::time::Instant
1223
// Should this be changed upstream?
@@ -49,3 +60,68 @@ pub fn validate_clvm_and_signature(
4960
// Collect results
5061
Ok(conditions)
5162
}
63+
64+
// TODO: This function is copied here because the upstream doesn't support custom dialects, and
65+
// we want to use the debug dialect for testing Rue puzzles in the simulator.
66+
// Should this be changed upstream?
67+
#[allow(clippy::type_complexity)]
68+
pub fn run_spendbundle(
69+
a: &mut Allocator,
70+
spend_bundle: &SpendBundle,
71+
max_cost: u64,
72+
flags: u32,
73+
constants: &ConsensusConstants,
74+
) -> Result<(SpendBundleConditions, Vec<(PublicKey, Bytes)>), ValidationErr> {
75+
// below is an adapted version of the code from run_block_generators::run_block_generator2()
76+
// it assumes no block references are passed in
77+
let mut cost_left = max_cost;
78+
let mut ret = SpendBundleConditions::default();
79+
let mut state = ParseState::default();
80+
// We don't pay the size cost (nor execution cost) of being wrapped by a
81+
// quote (in solution_generator).
82+
let generator_length_without_quote = calculate_generator_length(&spend_bundle.coin_spends) - 2;
83+
84+
let byte_cost = generator_length_without_quote as u64 * constants.cost_per_byte;
85+
subtract_cost(a, &mut cost_left, byte_cost)?;
86+
87+
for coin_spend in &spend_bundle.coin_spends {
88+
// process the spend
89+
let puz = node_from_bytes(a, coin_spend.puzzle_reveal.as_slice())?;
90+
let sol = node_from_bytes(a, coin_spend.solution.as_slice())?;
91+
let parent = a.new_atom(coin_spend.coin.parent_coin_info.as_slice())?;
92+
let amount = a.new_number(coin_spend.coin.amount.into())?;
93+
let Reduction(clvm_cost, conditions) = run_puzzle_with_cost(a, puz, sol, cost_left, false)?;
94+
95+
ret.execution_cost += clvm_cost;
96+
subtract_cost(a, &mut cost_left, clvm_cost)?;
97+
98+
let buf = tree_hash(a, puz);
99+
if coin_spend.coin.puzzle_hash != buf.into() {
100+
return Err(ValidationErr(puz, ErrorCode::WrongPuzzleHash));
101+
}
102+
let puzzle_hash = a.new_atom(&buf)?;
103+
let spend = process_single_spend::<MempoolVisitor>(
104+
a,
105+
&mut ret,
106+
&mut state,
107+
parent,
108+
puzzle_hash,
109+
amount,
110+
conditions,
111+
flags,
112+
&mut cost_left,
113+
clvm_cost,
114+
constants,
115+
)?;
116+
117+
if (spend.flags & ELIGIBLE_FOR_DEDUP) != 0 && (flags & COMPUTE_FINGERPRINT) != 0 {
118+
spend.fingerprint = compute_puzzle_fingerprint(a, conditions)?;
119+
}
120+
}
121+
122+
validate_conditions(a, &ret, &state, a.nil(), flags)?;
123+
124+
assert!(max_cost >= cost_left);
125+
ret.cost = max_cost - cost_left;
126+
Ok((ret, state.pkm_pairs))
127+
}

0 commit comments

Comments
 (0)