Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rework py api #97

Draft
wants to merge 81 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
3fea64f
Merge pull request #80 from Chia-Network/fix-builds
richardkiss May 20, 2021
0903e39
Remove obsolete api.
richardkiss Mar 4, 2021
b4a957e
First crack at gateway.
richardkiss Mar 4, 2021
91fa184
Checkpoint.
richardkiss Mar 4, 2021
b7dd52f
Checkpoint.
richardkiss Mar 4, 2021
f002241
Checkpoint.
richardkiss Mar 5, 2021
31a4b6a
Checkpoint.
richardkiss Mar 5, 2021
a0a1c69
Checkpoint.
richardkiss Mar 5, 2021
f23452c
First crack at returning `PyIntNode`.
richardkiss Mar 5, 2021
f24ae7b
More methods.
richardkiss Mar 6, 2021
c7a9287
Checkpoint.
richardkiss Mar 6, 2021
262aeae
Checkpoint.
richardkiss Mar 6, 2021
8583282
Checkpoint. Yikes.
richardkiss Mar 9, 2021
d4c6978
Checkpoint. Compiles.
richardkiss Mar 9, 2021
27d7893
Compiles, can create new atom and pair.
richardkiss Mar 10, 2021
287aba9
Got `run_program` not completely failing.
richardkiss Mar 11, 2021
5b2c669
Maybe works now?
richardkiss Mar 12, 2021
cda5166
More in `PyNaNode`.
richardkiss Mar 13, 2021
98ccf3e
Remove `println!` debug messages.
richardkiss Mar 13, 2021
8647233
Run `cargo fix`.
richardkiss Mar 14, 2021
40848e6
Do `cargo clippy`.
richardkiss Mar 14, 2021
b5dbd5a
Faster `None`.
richardkiss Mar 14, 2021
e6e0d41
Checkpoint. Almost have py operators working.
richardkiss Mar 14, 2021
a25f7ff
Call back into python seems to work now.
richardkiss Mar 14, 2021
45c30ac
Fix problem with errors.
richardkiss Mar 15, 2021
fdcd422
Checkpoint.
richardkiss Mar 15, 2021
cff49ec
Checkpoint. Call into python works a bit more.
richardkiss Mar 15, 2021
6d84a09
First crack at `py_native_mapping`.
richardkiss Mar 16, 2021
73f42d7
Lots of tests passing!
richardkiss Mar 16, 2021
44d839f
More tests passing!
richardkiss Mar 17, 2021
0471077
Remove tons of stuff, cargo clippy.
richardkiss Mar 17, 2021
7f78bb1
Rename `PyNaNode` to `PyNode`.
richardkiss Mar 17, 2021
7947f4e
More simplification.
richardkiss Mar 18, 2021
f794a26
Hash by id.
richardkiss Mar 18, 2021
3dd2865
Rename file.
richardkiss Mar 18, 2021
39e0853
Make `PyView` non-optional.
richardkiss Mar 18, 2021
5c5ffa0
Add `PyIntNode`.
richardkiss Mar 24, 2021
23bbb9c
Checkpoint of `Dialect`.
richardkiss Mar 25, 2021
33cad2a
Fix clippy.
richardkiss Mar 25, 2021
8bf20a1
First crack at `Dialect` actually working!
richardkiss Mar 26, 2021
f00ea74
Rename checkpoint.
richardkiss Mar 27, 2021
8c4aee0
More rename.
richardkiss Mar 27, 2021
a2065c1
First gross crack at `MultiOpFnE`.
richardkiss Apr 1, 2021
c58ee9a
Rename to `ArenaObject`.
richardkiss Apr 9, 2021
bd9ec94
Deprecate `STRICT` and be explicit about fallback function.
richardkiss Apr 9, 2021
7e7a7bc
Add api to `Arena`.
richardkiss Apr 15, 2021
8f6417e
Minor refactor.
richardkiss Apr 30, 2021
296793f
Use `PyAny` instead of `PyCell<CLVMObject>`.
richardkiss Apr 30, 2021
33d279e
Deal with import loops.
richardkiss May 4, 2021
8c234a0
Cast to `usize` instead of `*const PyObject`.
richardkiss May 6, 2021
1bd36bf
Get rid of most `CLVMObject` references.
richardkiss May 6, 2021
c7b845c
Use `&[u8]` instead of `u8` for apply & quote.
richardkiss May 10, 2021
9fecb12
Remove obsolete API.
richardkiss May 10, 2021
b81346d
Add `error_bridge` and bridge to allowing calling native `OpFn` from py.
richardkiss May 11, 2021
78c376a
Clippy
richardkiss May 11, 2021
ae2f556
Reverse `NATIVE_OP_UNKNOWN_STRICT` and counterpart.
richardkiss May 11, 2021
5576cf1
Add `Dialect.update`.
richardkiss May 11, 2021
dabce63
Abstract out last `CLVMObject` reference.
richardkiss May 11, 2021
a8e7b66
Finish generalizing `bridge_constructor`.
richardkiss May 12, 2021
12721bf
Need `&PyCell<PyArena>` in `native_for_py`.
richardkiss May 12, 2021
c6c91b1
Get rid of `CLVMObject` in native code.
richardkiss May 12, 2021
2379a6a
Many `clvm_tools` tests now pass.
richardkiss May 13, 2021
16f0832
Ditch `ArenaObject`.
richardkiss May 13, 2021
5f1c713
Delete a bunch of stuff.
richardkiss May 13, 2021
e28a462
Fix a test.
richardkiss May 13, 2021
dd376c4
Fix more tests.
richardkiss May 13, 2021
3341954
Require `to_python` in `Dialect` constructor.
richardkiss May 14, 2021
698c6bd
checkpoint
richardkiss May 18, 2021
8babcbe
Works!!
richardkiss May 18, 2021
f3ac35a
Tidy up a bit.
richardkiss May 19, 2021
636c226
Get rid of `PyView`.
richardkiss May 19, 2021
1f2ac7e
Rename `PyArena` to `Arena`.
richardkiss May 19, 2021
00df1af
Add comments.
richardkiss May 19, 2021
ede6ca9
Prefer `PyRef` over `PyCell`.
richardkiss May 22, 2021
d167ebe
Merge remote-tracking branch 'chia/main' into rework_py_api
richardkiss Jun 30, 2021
e4223c9
Factor out `BridgeCache`.
richardkiss Jul 1, 2021
ee8ebab
Improve `BridgeCache`.
richardkiss Jul 1, 2021
ce0b718
Merge remote-tracking branch 'chia/main' into rework_py_api
richardkiss Jul 2, 2021
50b3536
Use `&[u8]` for opcode instead of `u8`.
richardkiss Jul 2, 2021
b7d8ff9
Merge remote-tracking branch 'chia/main' into rework_py_api
richardkiss Jul 2, 2021
f1f65cb
Merge remote-tracking branch 'origin/main' into rework_py_api
richardkiss Jul 2, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 86 additions & 6 deletions src/py/api.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,104 @@
use std::cell::RefMut;

use pyo3::prelude::*;
use pyo3::types::{PyBytes, PyDict};
use pyo3::wrap_pyfunction;

use crate::allocator::Allocator;
use crate::core_ops::*;
use crate::err_utils::err;
use crate::more_ops::*;
use crate::node::Node;
use crate::serialize::node_to_bytes;

use super::arena::Arena;
use super::dialect::{Dialect, PyMultiOpFn};
use super::f_table::OpFn;
use super::lazy_node::LazyNode;
use super::native_op::NativeOp;
use super::run_program::{
__pyo3_get_function_deserialize_and_run_program,
__pyo3_get_function_deserialize_and_run_program2,
__pyo3_get_function_serialize_and_run_program, __pyo3_get_function_serialized_length,
__pyo3_get_function_deserialize_and_run_program2, __pyo3_get_function_serialized_length,
STRICT_MODE,
};

#[pyfunction]
pub fn native_opcodes_dict(py: Python) -> PyResult<PyObject> {
let opcode_lookup: [(OpFn, &str); 30] = [
(op_if, "op_if"),
(op_cons, "op_cons"),
(op_first, "op_first"),
(op_rest, "op_rest"),
(op_listp, "op_listp"),
(op_raise, "op_raise"),
(op_eq, "op_eq"),
(op_sha256, "op_sha256"),
(op_add, "op_add"),
(op_subtract, "op_subtract"),
(op_multiply, "op_multiply"),
(op_divmod, "op_divmod"),
(op_substr, "op_substr"),
(op_strlen, "op_strlen"),
(op_point_add, "op_point_add"),
(op_pubkey_for_exp, "op_pubkey_for_exp"),
(op_concat, "op_concat"),
(op_gr, "op_gr"),
(op_gr_bytes, "op_gr_bytes"),
(op_logand, "op_logand"),
(op_logior, "op_logior"),
(op_logxor, "op_logxor"),
(op_lognot, "op_lognot"),
(op_ash, "op_ash"),
(op_lsh, "op_lsh"),
(op_not, "op_not"),
(op_any, "op_any"),
(op_all, "op_all"),
(op_softfork, "op_softfork"),
(op_div, "op_div"),
];
let r = PyDict::new(py);
for (f, name) in opcode_lookup.iter() {
r.set_item(name, PyCell::new(py, NativeOp::new(*f))?)?;
}
Ok(r.to_object(py))
}

#[pyfunction]
fn serialize_to_bytes<'p>(py: Python<'p>, sexp: &PyAny) -> PyResult<&'p PyBytes> {
let arena_cell = Arena::new_cell(py)?;
let arena = arena_cell.borrow();
let mut allocator_refcell: RefMut<Allocator> = arena.allocator();
let allocator: &mut Allocator = &mut allocator_refcell as &mut Allocator;

let ptr = arena.as_native(py, allocator, sexp)?;

let node = Node::new(allocator, ptr);
let s: Vec<u8> = node_to_bytes(&node)?;
Ok(PyBytes::new(py, &s))
}

/// This module is a python module implemented in Rust.
#[pymodule]
fn clvm_rs(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_function(wrap_pyfunction!(serialize_and_run_program, m)?)?;
m.add_function(wrap_pyfunction!(deserialize_and_run_program, m)?)?;
m.add_function(wrap_pyfunction!(deserialize_and_run_program2, m)?)?;
m.add("STRICT_MODE", STRICT_MODE)?;
m.add_class::<Arena>()?;
m.add_class::<Dialect>()?;
m.add_class::<LazyNode>()?;

m.add_function(wrap_pyfunction!(native_opcodes_dict, m)?)?;
m.add_function(wrap_pyfunction!(serialized_length, m)?)?;

m.add(
"NATIVE_OP_UNKNOWN_STRICT",
PyMultiOpFn::new(|_a, b, _op, _d| err(b, "unimplemented operator")),
)?;

m.add("NATIVE_OP_UNKNOWN_NON_STRICT", PyMultiOpFn::new(op_unknown))?;

m.add_function(wrap_pyfunction!(serialize_to_bytes, m)?)?;

m.add_function(wrap_pyfunction!(deserialize_and_run_program, m)?)?;
m.add_function(wrap_pyfunction!(deserialize_and_run_program2, m)?)?;
m.add("STRICT_MODE", STRICT_MODE)?;

Ok(())
}
86 changes: 86 additions & 0 deletions src/py/arena.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/// An `Arena` is a collection of objects representing a program and
/// its arguments, and intermediate values reached while running
/// a program. Objects can be created in an `Arena` but are never
/// dropped until the `Arena` is dropped.
use std::cell::{RefCell, RefMut};

use pyo3::prelude::pyclass;
use pyo3::prelude::*;

use super::bridge_cache::BridgeCache;
use crate::allocator::{Allocator, NodePtr};
use crate::serialize::node_from_bytes;

#[pyclass(subclass, unsendable)]
pub struct Arena {
arena: RefCell<Allocator>,
cache: BridgeCache,
}

#[pymethods]
impl Arena {
#[new]
pub fn new(py: Python, new_obj_f: PyObject) -> PyResult<Self> {
Ok(Arena {
arena: RefCell::new(Allocator::default()),
cache: BridgeCache::new(py, new_obj_f)?,
})
}

/// deserialize `bytes` into an object in this `Arena`
pub fn deserialize<'p>(&self, py: Python<'p>, blob: &[u8]) -> PyResult<&'p PyAny> {
let allocator: &mut Allocator = &mut self.allocator() as &mut Allocator;
let ptr = node_from_bytes(allocator, blob)?;
self.as_python(py, allocator, ptr)
}

/// copy this python object into this `Arena` if it's not yet in the cache
/// (otherwise it returns the previously cached object)
pub fn include<'p>(&self, py: Python<'p>, obj: &'p PyAny) -> PyResult<&'p PyAny> {
let allocator = &mut self.allocator();
let ptr = self.as_native(py, allocator, obj)?;
self.as_python(py, allocator, ptr)
}

/// copy this python object into this `Arena` if it's not yet in the cache
/// (otherwise it returns the previously cached object)
pub fn ptr_for_obj(&self, py: Python, obj: &PyAny) -> PyResult<i32> {
self.as_native(py, &mut self.allocator(), obj)
}
}

impl Arena {
pub fn new_cell_obj(py: Python, new_obj_f: PyObject) -> PyResult<&PyCell<Self>> {
PyCell::new(py, Arena::new(py, new_obj_f)?)
}

pub fn new_cell(py: Python) -> PyResult<&PyCell<Self>> {
Self::new_cell_obj(py, py.eval("lambda sexp: sexp", None, None)?.to_object(py))
}

pub fn obj_for_ptr<'p>(&self, py: Python<'p>, ptr: i32) -> PyResult<&'p PyAny> {
self.as_python(py, &mut self.allocator(), ptr)
}

pub fn allocator(&self) -> RefMut<Allocator> {
self.arena.borrow_mut()
}

pub fn as_native(
&self,
py: Python,
allocator: &mut Allocator,
obj: &PyAny,
) -> PyResult<NodePtr> {
self.cache.as_native(py, allocator, obj)
}

pub fn as_python<'p>(
&self,
py: Python<'p>,
allocator: &mut Allocator,
ptr: NodePtr,
) -> PyResult<&'p PyAny> {
self.cache.as_python(py, allocator, ptr)
}
}
Loading