Browse Source

:construction: on-chain component serialization

Danilo Guanabara 2 months ago
parent
commit
e24e8fd8b2

+ 1 - 0
Cargo.lock

@@ -924,6 +924,7 @@ dependencies = [
 name = "bolt-types"
 version = "0.2.4"
 dependencies = [
+ "anchor-lang",
  "bolt-lang",
 ]
 

+ 1 - 1
clients/typescript/src/index.ts

@@ -1,4 +1,4 @@
-import { Keypair, PublicKey } from "@solana/web3.js";
+import { PublicKey } from "@solana/web3.js";
 import BN from "bn.js";
 import { PROGRAM_ID as WORLD_PROGRAM_ID } from "./generated";
 import { World as WORLD_PROGRAM_IDL } from "./generated/types";

+ 3 - 1
crates/bolt-cli/src/templates/component/mod.rs

@@ -38,13 +38,15 @@ pub fn component_type(idl: &Idl, component_id: &str) -> Result<String> {
         Some(ty) => ty,
         None => return Err(anyhow::anyhow!("Component type not found in IDL")),
     };
+
+    let component_name = component_account.name.to_upper_camel_case();
+    println!("Component name: {}", component_name);
     let component_code = component_to_rust_code(type_def, component_id);
     let types_code = component_types_to_rust_code(&idl.types, &component_account.name);
     Ok(format!(
         r#"use bolt_lang::*;
 
 #[component_deserialize]
-#[derive(Clone, Copy)]
 {}
 
 {}

+ 7 - 1
crates/bolt-lang/attribute/component-deserialize/src/lib.rs

@@ -63,7 +63,13 @@ pub fn component_deserialize(_attr: TokenStream, item: TokenStream) -> TokenStre
 
         #[automatically_derived]
         impl bolt_lang::AccountSerialize for #name {
-            fn try_serialize<W>(&self, _writer: &mut W) -> Result<()> {
+            fn try_serialize<W: std::io::Write>(&self, writer: &mut W) -> Result<()> {
+                if writer.write_all(Self::DISCRIMINATOR).is_err() {
+                    return Err(bolt_lang::AccountDidNotSerializeErrorCode.into());
+                }
+                if bolt_lang::AnchorSerialize::serialize(self, writer).is_err() {
+                    return Err(bolt_lang::AccountDidNotSerializeErrorCode.into());
+                }
                 Ok(())
             }
         }

+ 8 - 3
crates/bolt-lang/src/account.rs

@@ -43,11 +43,16 @@ impl<'info, T: anchor_lang::ToAccountMetas, const P0: u128, const P1: u128> anch
     }
 }
 
-impl<'info, T: anchor_lang::AccountsExit<'info>, const P0: u128, const P1: u128> anchor_lang::AccountsExit<'info>
+impl<'info, T: anchor_lang::ToAccountInfos<'info> + anchor_lang::ToAccountInfo<'info> + anchor_lang::AccountSerialize + anchor_lang::AccountsExit<'info>, const P0: u128, const P1: u128> anchor_lang::AccountsExit<'info>
     for BoltAccount<T, P0, P1>
 {
-    fn exit(&self, program_id: &Pubkey) -> Result<()> {
-        self.0.exit(program_id)
+    fn exit(&self, _program_id: &Pubkey) -> Result<()> {
+        let info = self.0.to_account_info();
+        let mut data = info.try_borrow_mut_data()?;
+        let dst: &mut [u8] = &mut data;
+        let mut writer = crate::bpf_writer::BpfWriter::new(dst);
+        self.0.try_serialize(&mut writer)?;
+        Ok(())
     }
 }
 

+ 48 - 0
crates/bolt-lang/src/bpf_writer.rs

@@ -0,0 +1,48 @@
+/// Implementation from Anchor.
+
+use solana_program::program_memory::sol_memcpy;
+use std::cmp;
+use std::io::{self, Write};
+
+#[derive(Debug, Default)]
+pub struct BpfWriter<T> {
+    inner: T,
+    pub pos: u64,
+}
+
+impl<T> BpfWriter<T> {
+    pub fn new(inner: T) -> Self {
+        Self { inner, pos: 0 }
+    }
+}
+
+impl Write for BpfWriter<&mut [u8]> {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        if self.pos >= self.inner.len() as u64 {
+            return Ok(0);
+        }
+
+        let amt = cmp::min(
+            self.inner.len().saturating_sub(self.pos as usize),
+            buf.len(),
+        );
+        sol_memcpy(&mut self.inner[(self.pos as usize)..], buf, amt);
+        self.pos += amt as u64;
+        Ok(amt)
+    }
+
+    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+        if self.write(buf)? == buf.len() {
+            Ok(())
+        } else {
+            Err(io::Error::new(
+                io::ErrorKind::WriteZero,
+                "failed to write whole buffer",
+            ))
+        }
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        Ok(())
+    }
+}

+ 2 - 0
crates/bolt-lang/src/lib.rs

@@ -2,12 +2,14 @@ pub mod prelude;
 
 pub use anchor_lang;
 pub use anchor_lang::error::ErrorCode::AccountDidNotDeserialize as AccountDidNotDeserializeErrorCode;
+pub use anchor_lang::error::ErrorCode::AccountDidNotSerialize as AccountDidNotSerializeErrorCode;
 pub use anchor_lang::prelude::*;
 pub use anchor_lang::{
     AccountDeserialize, AccountSerialize, AnchorDeserialize, AnchorSerialize, Bumps, Result,
 };
 
 pub mod instructions;
+pub mod bpf_writer;
 pub use instructions::*;
 
 pub mod cpi;

+ 3 - 2
crates/types/Cargo.toml

@@ -1,6 +1,6 @@
 [package]
 name = "bolt-types"
-version.workspace = true
+version = "0.2.4"
 description = "Autogenerate types for the bolt language"
 edition = "2021"
 
@@ -9,4 +9,5 @@ crate-type = ["cdylib", "lib"]
 name = "bolt_types"
 
 [dependencies]
-bolt-lang.workspace = true
+bolt-lang.workspace = true
+anchor-lang.workspace = true

+ 0 - 2
crates/types/src/component_Fn1JzzEdyb55fsyduWS94mYHizGhJZuhvjX6DVvrmGbQ.rs

@@ -6,5 +6,3 @@ pub struct ComponentFn1JzzEdyb55fsyduWS94mYHizGhJZuhvjX6DVvrmGbQ {
     pub y: i64,
     pub z: i64,
 }
-
-pub use ComponentFn1JzzEdyb55fsyduWS94mYHizGhJZuhvjX6DVvrmGbQ as Position;

+ 5 - 1
examples/system-simple-movement/src/lib.rs

@@ -14,7 +14,11 @@ pub mod system_simple_movement {
         };
         ctx.accounts.position.x += dx;
         ctx.accounts.position.y += dy;
-
+        msg!("Position: {:?}", ctx.accounts.position.to_account_info().try_borrow_data()?);
+        ctx.accounts.position.exit(&crate::id())?;
+        msg!("Position: {:?}", ctx.accounts.position.to_account_info().try_borrow_data()?);
+        panic!();
+        use std::io::Write;
         Ok(())
     }