IDL (Interface Definition Language) एक JSON फ़ाइल है जो यह वर्णित करती है कि Solana प्रोग्राम के साथ कैसे इंटरैक्ट किया जाए। यह स्वचालित रूप से Anchor फ्रेमवर्क द्वारा जनरेट की जाती है।
“initialize” नामक फंक्शन में कुछ भी खास नहीं है — यह वह नाम है जिसे Anchor चुनता है। इस ट्यूटोरियल में हम यह सीखेंगे कि typescript यूनिट टेस्ट्स उचित फंक्शन को कैसे “खोज” पाते हैं।
आइए anchor-function-tutorial नामक एक नया प्रोजेक्ट बनाएं और बाकी सब कुछ समान रखते हुए, initialize फंक्शन का नाम बदलकर boaty_mc_boatface कर दें।
pub fn boaty_mc_boatface(ctx: Context<Initialize>) -> Result<()> {
Ok(())
}
अब टेस्ट को निम्नलिखित में बदलें:
it("Call boaty mcboatface", async () => {
// Add your test here.
const tx = await program.methods.boatyMcBoatface().rpc();
console.log("Your transaction signature", tx);
});
अब anchor test --skip-local-validator के साथ टेस्ट रन करें।
यह उम्मीद के मुताबिक रन होता है। तो यह जादू कैसे काम कर गया?
टेस्ट्स को initialize फंक्शन के बारे में कैसे पता चलता है?
जब Anchor एक Solana प्रोग्राम बिल्ड करता है, तो यह एक IDL (Interface Definition Language) बनाता है।
यह target/idl/anchor_function_tutorial.json. में स्टोर होता है। इस फ़ाइल को anchor_function_tutorial.json कहा जाता है क्योंकि प्रोग्राम का नाम anchor_function_tutorial है। ध्यान दें कि Anchor ने डैश को अंडरस्कोर में बदल दिया है!
आइए इसे खोलें।
{
"version": "0.1.0",
"name": "anchor_function_tutorial",
"instructions": [
{
"name": "boatyMcBoatface",
"accounts": [],
"args": []
}
]
}
“instructions” की सूची पब्लिक फेसिंग फंक्शन्स हैं जिन्हें प्रोग्राम सपोर्ट करता है, जो लगभग एक Ethereum कॉन्ट्रैक्ट पर external और public फंक्शन्स के बराबर हैं। Solana में एक IDL फ़ाइल Solidity में ABI फ़ाइल के समान भूमिका निभाती है, जो यह निर्दिष्ट करती है कि प्रोग्राम/कॉन्ट्रैक्ट के साथ कैसे इंटरैक्ट करना है।
हमने पहले देखा था कि हमारा फंक्शन कोई आर्ग्युमेंट नहीं लेता है, इसलिए
argsसूची खाली है। हम बाद में समझाएंगे कि “accounts” क्या है।
एक बात जो अलग दिखती है: Rust में फंक्शन्स snake_cased होते हैं, लेकिन Anchor उन्हें JavaScript लैंड में camelCased के रूप में फॉर्मेट करता है। यह भाषाओं की परंपराओं का सम्मान करने के लिए है: Rust अक्सर snake case का उपयोग करता है, और JavaScript आमतौर पर camel case का उपयोग करता है।
यह JSON फ़ाइल ही वह तरीका है जिससे “methods” ऑब्जेक्ट यह जानता है कि किन फंक्शन्स को सपोर्ट करना है।
जब हम टेस्ट रन करते हैं, तो हम इसके पास होने की उम्मीद करते हैं, जिसका अर्थ है कि टेस्ट सही ढंग से Solana प्रोग्राम को कॉल कर रहा है:

Exercise: u64 प्राप्त करने के लिए boaty_mc_boatface फंक्शन में एक आर्ग्युमेंट जोड़ें। anchor build फिर से रन करें। उसके बाद target/idl/anchor_function_tutorial.json फ़ाइल को दोबारा खोलें। यह कैसे बदलता है?
अब आइए एक ऐसा Solana प्रोग्राम बनाना शुरू करें जिसमें बेसिक जोड़ (addition) और घटाव (subtraction) के फंक्शन्स हों जो परिणाम को प्रिंट करते हों। Solana फंक्शन्स उस तरह से वैल्यूज रिटर्न नहीं कर सकते जैसे Solidity करता है, इसलिए हमें उन्हें प्रिंट करना होगा। (Solana में वैल्यूज पास करने के वैकल्पिक तरीके हैं जिन पर हम बाद में चर्चा करेंगे)। आइए इस तरह से दो फंक्शन्स बनाएं:
pub fn add(ctx: Context<Initialize>, a: u64, b: u64) -> Result<()> {
let sum = a + b;
msg!("Sum is {}", sum);
Ok(())
}
pub fn sub(ctx: Context<Initialize>, a: u64, b: u64) -> Result<()> {
let difference = a - b;
msg!("Difference is {}", difference);
Ok(())
}
और अपने यूनिट टेस्ट्स को निम्नलिखित में बदलें:
it("Should add", async () => {
const tx = await program.methods.add(new anchor.BN(1), new anchor.BN(2)).rpc();
console.log("Your transaction signature", tx);
});
it("Should sub", async () => {
const tx = await program.methods.sub( new anchor.BN(10), new anchor.BN(3)).rpc();
console.log("Your transaction signature", tx);
});
Exercise: mul, div, और modulo के लिए समान फंक्शन्स लागू करें, और प्रत्येक को ट्रिगर करने के लिए एक यूनिट टेस्ट लिखें।
Initialize struct के बारे में क्या?
अब यहां एक और छिपी हुई बात (sneaky thing) हो रही है। हमने Initialize struct को अछूता छोड़ दिया है और इसे फंक्शन्स के बीच दोबारा उपयोग कर रहे हैं। फिर से, नाम से कोई फर्क नहीं पड़ता। आइए struct का नाम बदलकर Empty कर दें और टेस्ट को दोबारा रन करें।
//...
// Change struct name here
pub fn add(ctx: Context<Empty>, a: u64, b: u64) -> Result<()> {
let sum = a + b;
msg!("Sum is {}", sum);
Ok(())
}
//...
// Change struct name here too
#[derive(Accounts)]
pub struct Empty {}
फिर से, यहाँ Empty नाम पूरी तरह से मनमाना (arbitrary) है।
Exercise: struct का नाम Empty से बदलकर BoatyMcBoatface कर दें और टेस्ट्स को फिर से रन करें।
#[derive(Accounts)] struct क्या है?
यह # सिंटैक्स Anchor फ्रेमवर्क द्वारा परिभाषित एक Rust attribute है। हम इसे आगे के ट्यूटोरियल में और स्पष्ट करेंगे। अभी के लिए, हम IDL में accounts की पर ध्यान देना चाहते हैं और यह प्रोग्राम में परिभाषित struct से कैसे संबंधित है।
Accounts IDL key
नीचे हमने हमारे उपरोक्त प्रोग्राम के IDL का स्क्रीनशॉट दिया है। ताकि हम उस Rust Attribute #[derive(Accounts)] में “Accounts” और IDL में “accounts” की (key) के बीच के संबंध को देख सकें:

हमारे उदाहरण में, ऊपर दिए गए JSON IDL में purple arrow द्वारा चिह्नित accounts की (key) खाली है। लेकिन अधिकांश उपयोगी Solana ट्रांजैक्शन्स के मामले में ऐसा नहीं होता है, जैसा कि हम बाद में सीखेंगे।
क्योंकि BoatyMcBoatface के लिए हमारा अकाउंट struct खाली है, इसलिए IDL में accounts सूची भी खाली है।
अब देखते हैं कि क्या होता है जब struct खाली नहीं (non-empty) होता है। नीचे दिए गए कोड को कॉपी करें और lib.rs के कॉन्टेंट्स को बदल दें।
use anchor_lang::prelude::*;
declare_id!("8PSAL9t1RMb7BcewhsSFrRQDq61Y7YXC5kHUxMk5b39Z");
#[program]
pub mod anchor_function_tutorial {
use super::*;
pub fn non_empty_account_example(ctx: Context<NonEmptyAccountExample>) -> Result<()> {
Ok(())
}
}
#[derive(Accounts)]
pub struct NonEmptyAccountExample<'info> {
signer: Signer<'info>,
another_signer: Signer<'info>,
}
अब anchor build रन करें - आइए देखें कि हमें नए IDL में क्या वापस मिलता है।
{
"version": "0.1.0",
"name": "anchor_function_tutorial",
"instructions": [
{
"name": "nonEmptyAccountExample",
"accounts": [
{
"name": "signer",
"isMut": false,
"isSigner": true
},
{
"name": "anotherSigner",
"isMut": false,
"isSigner": true
}
],
"args": []
}
],
"metadata": {
"address": "8PSAL9t1RMb7BcewhsSFrRQDq61Y7YXC5kHUxMk5b39Z"
}
}
ध्यान दें कि “accounts” अब खाली नहीं है और struct के फील्ड्स से भरा गया है: “signer” और “anotherSigner” (ध्यान दें कि another_signer snake case से camel case में बदल गया है)। IDL को उस struct से मेल खाने के लिए अपडेट किया गया है जिसे हमने अभी बदला है, विशेष रूप से हमारे द्वारा जोड़े गए अकाउंट्स की संख्या के साथ।
हम आगामी ट्यूटोरियल में “Signer” के बारे में अधिक गहराई से जानेंगे, लेकिन अभी के लिए आप इसे Ethereum में tx.origin के समान मान सकते हैं।
एक प्रोग्राम और IDL का दूसरा उदाहरण।
अब तक हमने जो कुछ भी सीखा है उसे संक्षेप में समझने के लिए, आइए विभिन्न फंक्शन्स और Account structs के साथ एक और प्रोग्राम बनाएं।
use anchor_lang::prelude::*;
declare_id!("8PSAL9t1RMb7BcewhsSFrRQDq61Y7YXC5kHUxMk5b39Z");
#[program]
pub mod anchor_function_tutorial {
use super::*;
pub fn function_a(ctx: Context<NonEmptyAccountExample>) -> Result<()> {
Ok(())
}
pub fn function_b(ctx: Context<Empty>, firstArg: u64) -> Result<()> {
Ok(())
}
}
#[derive(Accounts)]
pub struct NonEmptyAccountExample<'info> {
signer: Signer<'info>,
another_signer: Signer<'info>,
}
#[derive(Accounts)]
pub struct Empty {}
अब इसे anchor build के साथ बिल्ड करें
आइए फिर से IDL फ़ाइल target/idl/anchor_function_tutorial.json को देखें और इन फ़ाइलों को अगल-बगल (side by side) रखें:

क्या आप IDL फ़ाइल और ऊपर दिए गए प्रोग्राम के बीच का संबंध देख सकते हैं?
फंक्शन function_a में कोई आर्ग्युमेंट नहीं है और यह IDL में args की (key) के तहत एक खाली ऐरे (empty array) के रूप में दिखाई देता है।
इसका Context, NonEmptyAccountExample struct लेता है। इस NonEmptyAccountExample struct में दो signer फील्ड्स हैं: signer और another_signer। ध्यान दें कि ये function_a के लिए IDL में account की (key) के तत्वों के रूप में दोहराए गए हैं। आप देख सकते हैं कि Anchor ने IDL में Rust के snake case का camel case में अनुवाद किया है।
Anchor 0.30 के लिए अपडेट Anchor अब स्वचालित रूप से यह ट्रांसलेशन नहीं करता है (release notes)।
फंक्शन function_b एक u64 आर्ग्युमेंट लेता है। इसका context struct खाली है, इसलिए function_b के लिए IDL में accounts की (key) एक खाली ऐरे है।
सामान्य तौर पर, हम उम्मीद करते हैं कि IDL की accounts की (key) में आइटम्स का ऐरे उस account struct की कीज़ (keys) से मेल खाएगा जिसे फंक्शन अपने ctx आर्ग्युमेंट में लेता है।
सारांश
इस अध्याय में:
- हमने सीखा कि Solana एक IDL (Interface Definition Language) का उपयोग यह दिखाने के लिए करता है कि Solana प्रोग्राम के साथ कैसे इंटरैक्ट किया जाए और IDL में कौन से फील्ड्स दिखाई देते हैं।
- हमने
#[derive(Accounts)]द्वारा मॉडिफाई किए गए struct और फंक्शन आर्ग्युमेंट्स के साथ इसके संबंध को पेश किया। - Anchor, Typescript टेस्ट्स में Rust के snake_case फंक्शन्स को camelCase फंक्शन्स के रूप में समझता है।
मूल रूप से 10 फरवरी, 2024 को प्रकाशित