Skip to content

Commit 67a4679

Browse files
ngundotrafebo
andauthored
Include kinobi IDL (#84)
* write idl/asset-program.kinobi.json * add support for kinobi idls * use include_kinobi_idl instead of include_idl * remove unused deps * Fix lint * Add include setting to upload action * Add kinobi idl --------- Co-authored-by: febo <febo@nifty-oss.org>
1 parent c68f221 commit 67a4679

File tree

8 files changed

+87
-21
lines changed

8 files changed

+87
-21
lines changed

.github/workflows/build-programs.yml

+1
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,5 @@ jobs:
7272
name: program-builds
7373
# First wildcard ensures exported paths are consistently under the programs folder.
7474
path: ./program*/.bin/*.so
75+
include-hidden-files: true
7576
if-no-files-found: error

configs/kinobi-asset.cjs

+3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ const anchorIdl = require("@kinobi-so/nodes-from-anchor");
22
const jsRenderer = require("@kinobi-so/renderers-js-umi");
33
const rustRenderer = require("@kinobi-so/renderers-rust");
44
const k = require("kinobi");
5+
const { writeFileSync } = require("fs");
56

67
// Paths.
78
const path = require("path");
@@ -627,3 +628,5 @@ kinobi.accept(
627628
}
628629
)
629630
);
631+
632+
writeFileSync(path.join(idlDir, "asset-program.kinobi.json"), kinobi.getJson());

idls/asset-program.kinobi.json

+1
Large diffs are not rendered by default.

include-idl-cli/src/main.rs

+15-9
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use std::path::PathBuf;
22

3-
use goblin::error::Result;
4-
use include_idl::parse_idl_from_program_binary;
3+
// use goblin::error::Result;
4+
use include_idl::parse::{parse_idl_from_program_binary, IdlType};
55

6-
use clap::{Parser, Subcommand};
6+
use clap::{Error, Parser, Subcommand};
77

88
#[derive(Parser)]
99
#[command(version, about, long_about = None)]
@@ -17,19 +17,25 @@ enum Commands {
1717
Parse {
1818
/// Read IDL from a solana program binary
1919
path: PathBuf,
20+
idl_type: IdlType,
2021
},
2122
}
2223

23-
pub fn main() -> Result<()> {
24+
// This example uses ArgEnum, so this might not be necessary.
25+
26+
pub fn main() -> Result<(), Error> {
2427
let cli = Cli::parse();
2528

2629
match &cli.command {
27-
Some(Commands::Parse { path }) => {
30+
Some(Commands::Parse { path, idl_type }) => {
2831
let buffer = std::fs::read(path).expect("Could not read file.");
29-
let idl = parse_idl_from_program_binary(&buffer)?;
30-
println!(" Program IDL");
31-
println!("============================");
32-
println!("{}", idl);
32+
if let Ok(idl) = parse_idl_from_program_binary(&buffer, idl_type.clone()) {
33+
println!(" Program IDL");
34+
println!("============================");
35+
println!("{}", idl);
36+
} else {
37+
println!("Could not find {:?} IDL in program binary", idl_type);
38+
}
3339
}
3440
None => {}
3541
}

include-idl/src/lib.rs

+15-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
#[cfg(feature = "parse")]
2-
mod parse;
3-
#[cfg(feature = "parse")]
4-
pub use parse::parse_idl_from_program_binary;
2+
pub mod parse;
53

64
#[cfg(feature = "shrink")]
75
mod shrink;
6+
87
#[cfg(feature = "shrink")]
98
pub use shrink::compress_idl;
109

@@ -20,3 +19,16 @@ macro_rules! include_idl {
2019
pub static IDL_BYTES: &[u8] = include_bytes!($s);
2120
};
2221
}
22+
23+
#[macro_export]
24+
macro_rules! include_kinobi_idl {
25+
($s:expr) => {
26+
#[cfg_attr(
27+
any(target_arch = "sbf", target_arch = "bpf"),
28+
link_section = ".kinobi.idl"
29+
)]
30+
#[allow(dead_code)]
31+
#[no_mangle]
32+
pub static KINOBI_IDL_BYTES: &[u8] = include_bytes!($s);
33+
};
34+
}

include-idl/src/parse.rs

+43-5
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,55 @@
11
#[cfg(feature = "parse")]
22
use {
3-
flate2::bufread::ZlibDecoder, goblin::elf::Elf, goblin::error::Result, serde_json::Value,
4-
std::io::Read,
3+
flate2::bufread::ZlibDecoder, goblin::elf::Elf, serde_json::Value, std::fmt, std::io::Read,
4+
std::str::FromStr,
55
};
66

7-
#[cfg(feature = "parse")]
8-
pub fn parse_idl_from_program_binary(buffer: &[u8]) -> Result<Value> {
7+
#[derive(Clone, Debug)]
8+
pub enum IdlType {
9+
Anchor,
10+
Kinobi,
11+
}
12+
13+
impl fmt::Display for IdlType {
14+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
15+
match self {
16+
IdlType::Anchor => write!(f, "Anchor"),
17+
IdlType::Kinobi => write!(f, "Kinobi"),
18+
}
19+
}
20+
}
21+
22+
impl FromStr for IdlType {
23+
type Err = &'static str;
24+
25+
fn from_str(s: &str) -> Result<Self, &'static str> {
26+
match s.to_lowercase().as_str() {
27+
"anchor" => Ok(IdlType::Anchor),
28+
"kinobi" => Ok(IdlType::Kinobi),
29+
_ => Err("Invalid IDL type"),
30+
}
31+
}
32+
}
33+
34+
fn get_section_name(idl_type: IdlType) -> String {
35+
match idl_type {
36+
IdlType::Anchor => ".solana.idl".to_string(),
37+
IdlType::Kinobi => ".kinobi.idl".to_string(),
38+
}
39+
}
40+
41+
pub fn parse_idl_from_program_binary(
42+
buffer: &[u8],
43+
idl_type: IdlType,
44+
) -> goblin::error::Result<Value> {
945
let elf = Elf::parse(buffer)?;
1046

47+
let section_name = get_section_name(idl_type);
48+
1149
// Iterate over section headers and print information
1250
for sh in &elf.section_headers {
1351
let name = elf.shdr_strtab.get_at(sh.sh_name).unwrap_or("<invalid>");
14-
if name == ".solana.idl" {
52+
if name == section_name {
1553
// Get offset of .solana.idl section data
1654
let offset = sh.sh_offset as usize;
1755

programs/asset/program/build.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,17 @@ fn main() {
1111
.output()
1212
.expect("Failed to run shank");
1313

14+
let _output = Command::new("pnpm")
15+
.arg("generate:clients")
16+
.output()
17+
.expect("Failed to create the kinobi IDLs");
18+
1419
// Get the IDL path
15-
let idl_path = PathBuf::from("../../../idls").join("asset_program.json");
20+
let idl_path = PathBuf::from("../../../idls").join("asset-program.kinobi.json");
1621

1722
// Concat output path of compressed IDL
1823
let out_dir = env::var("OUT_DIR").unwrap();
19-
let dest_path = PathBuf::from(out_dir).join("idl.json.zip");
24+
let dest_path = PathBuf::from(out_dir).join("kinobi.idl.zip");
2025

2126
compress_idl(&idl_path, &dest_path);
2227
}

programs/asset/program/src/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@ pub mod utils;
1515
pub use solana_program;
1616

1717
#[cfg(not(feature = "no-entrypoint"))]
18-
use include_idl::include_idl;
18+
use include_idl::include_kinobi_idl;
1919

2020
#[cfg(not(feature = "no-entrypoint"))]
2121
use solana_security_txt::security_txt;
2222

2323
#[cfg(not(feature = "no-entrypoint"))]
24-
include_idl!(concat!(env!("OUT_DIR"), "/idl.json.zip"));
24+
include_kinobi_idl!(concat!(env!("OUT_DIR"), "/kinobi.idl.zip"));
2525

2626
#[cfg(not(feature = "no-entrypoint"))]
2727
security_txt! {

0 commit comments

Comments
 (0)