Skip to content

Commit

Permalink
Merge branch 'master' into lang-add-lazy-account
Browse files Browse the repository at this point in the history
  • Loading branch information
acheroncrypto committed Sep 1, 2024
2 parents 1bbebe2 + 467ae43 commit 92cdf0a
Show file tree
Hide file tree
Showing 28 changed files with 261 additions and 91 deletions.
5 changes: 4 additions & 1 deletion .github/issue_template.md
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
⚠️ Don't use issues for support questions ("How does x feature work in Anchor? How to do x in Anchor?"). Use the discord instead https://discord.gg/NHHGSXAnXk (but don't ping maintainers). ⚠️
⚠️ Don't use issues for support questions ("How does x feature work in Anchor? How to do x in Anchor?"). Instead:

- Check [Solana Stack Exchange](https://solana.stackexchange.com/) - chances are someone has already had the same issue, and there's already an answer there. If not, write a new question!
- See [the Anchor Discord](https://discord.gg/NHHGSXAnXk) (but don't ping maintainers). ⚠
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ The minor version will be incremented upon a breaking change and the patch versi

### Features

- ts: Add optional `options.blockhash` to `Provider.sendAndConfirm` ([#3070](https://github.com/coral-xyz/anchor/pull/3070)).
- ts: Add optional `commitment` parameter to `Program.addEventListener` ([#3052](https://github.com/coral-xyz/anchor/pull/3052)).
- cli, idl: Pass `cargo` args to IDL generation when building program or IDL ([#3059](https://github.com/coral-xyz/anchor/pull/3059)).
- cli: Add checks for incorrect usage of `idl-build` feature ([#3061](https://github.com/coral-xyz/anchor/pull/3061)).
Expand Down Expand Up @@ -41,6 +42,9 @@ The minor version will be incremented upon a breaking change and the patch versi
- spl: Add `burn_checked`, `mint_to_checked` and `approve_checked` instructions ([#3186]([https://github.com/coral-xyz/anchor/pull/3186)).
- cli: Migrate to `agave-install` when `solana_version` is `>= 1.18.19` ([#3185](https://github.com/coral-xyz/anchor/pull/3185)).
- idl: Add `IdlBuilder` ([#3188](https://github.com/coral-xyz/anchor/pull/3188)).
- cli: Make `clean` command also remove the `.anchor` directory ([#3192](https://github.com/coral-xyz/anchor/pull/3192)).
- lang: Deprecate `#[interface]` attribute ([#3195](https://github.com/coral-xyz/anchor/pull/3195)).
- ts: Include unresolved accounts in the resolution error message ([#3207](https://github.com/coral-xyz/anchor/pull/3207)).

### Fixes

Expand All @@ -58,6 +62,10 @@ The minor version will be incremented upon a breaking change and the patch versi
- lang: Fix compilation warnings due to unused deprecated program id macros ([#3170](https://github.com/coral-xyz/anchor/pull/3170)).
- ts: Remove `crypto-hash` dependency ([#3171](https://github.com/coral-xyz/anchor/pull/3171)).
- ts: Improve error message of unsupported `view` method ([#3177](https://github.com/coral-xyz/anchor/pull/3177)).
- idl: Fix panicking on tests ([#3197](https://github.com/coral-xyz/anchor/pull/3197)).
- lang: Remove `arrayref` dependency ([#3201](https://github.com/coral-xyz/anchor/pull/3201)).
- cli: Fix template code shouldn't escape ([#3210](https://github.com/coral-xyz/anchor/pull/3210)).
- idl: Fix using `address` constraint with non-const expressions ([#3216](https://github.com/coral-xyz/anchor/pull/3216)).

### Breaking

Expand All @@ -74,6 +82,7 @@ The minor version will be incremented upon a breaking change and the patch versi
- lang: Remove `discriminator` method from `Discriminator` trait ([#3163](https://github.com/coral-xyz/anchor/pull/3163)).
- docker: Upgrade `node` to 20.16.0 LTS ([#3179](https://github.com/coral-xyz/anchor/pull/3179)).
- ts: Change the `Program` constructor's `idl` parameter type to `any` ([#3181](https://github.com/coral-xyz/anchor/pull/3181)).
- lang, spl: Remove `borsh 0.9` support ([#3199](https://github.com/coral-xyz/anchor/pull/3199)).

## [0.30.1] - 2024-06-20

Expand Down
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion cli/src/rust_template.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ pub use initialize::*;
pub struct Initialize {}
pub fn handler(ctx: Context<Initialize>) -> Result<()> {
msg!("Greetings from: {{:?}}", ctx.program_id);
msg!("Greetings from: {:?}", ctx.program_id);
Ok(())
}
"#
Expand Down
3 changes: 1 addition & 2 deletions lang/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,9 @@ anchor-derive-space = { path = "./derive/space", version = "0.30.1" }
# `anchor-lang-idl` should only be included with `idl-build` feature
anchor-lang-idl = { path = "../idl", version = "0.1.1", optional = true }

arrayref = "0.3"
base64 = "0.21"
bincode = "1"
borsh = ">=0.9, <0.11"
borsh = "0.10.3"
bytemuck = "1"
solana-program = "1.17.3"
thiserror = "1"
15 changes: 10 additions & 5 deletions lang/attribute/account/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,16 @@ mod lazy;
/// - [`Owner`](./trait.Owner.html)
///
/// When implementing account serialization traits the first 8 bytes are
/// reserved for a unique account discriminator, self described by the first 8
/// bytes of the SHA256 of the account's Rust ident.
/// reserved for a unique account discriminator by default, self described by
/// the first 8 bytes of the SHA256 of the account's Rust ident. This is unless
/// the discriminator was overridden with the `discriminator` argument (see
/// [Arguments](#arguments)).
///
/// As a result, any calls to `AccountDeserialize`'s `try_deserialize` will
/// check this discriminator. If it doesn't match, an invalid account was given,
/// and the account deserialization will exit with an error.
///
/// # Args
/// # Arguments
///
/// - `discriminator`: Override the default 8-byte discriminator
///
Expand Down Expand Up @@ -86,8 +88,11 @@ mod lazy;
/// [`safety`](https://docs.rs/bytemuck/latest/bytemuck/trait.Pod.html#safety)
/// section before using.
///
/// Using `zero_copy` requires adding the following to your `cargo.toml` file:
/// `bytemuck = { version = "1.4.0", features = ["derive", "min_const_generics"]}`
/// Using `zero_copy` requires adding the following dependency to your `Cargo.toml` file:
///
/// ```toml
/// bytemuck = { version = "1.17", features = ["derive", "min_const_generics"] }
/// ```
#[proc_macro_attribute]
pub fn account(
args: proc_macro::TokenStream,
Expand Down
2 changes: 1 addition & 1 deletion lang/attribute/event/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use syn::parse_macro_input;
/// their programs that clients can subscribe to. Currently, this macro is for
/// structs only.
///
/// # Args
/// # Arguments
///
/// - `discriminator`: Override the default 8-byte discriminator
///
Expand Down
3 changes: 1 addition & 2 deletions lang/attribute/program/src/declare_program/mods/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,9 @@ fn gen_account(idl: &Idl) -> proc_macro2::TokenStream {
let if_statements = idl.accounts.iter().map(|acc| {
let name = format_ident!("{}", acc.name);
let disc = gen_discriminator(&acc.discriminator);
let disc_len = acc.discriminator.len();
quote! {
if value.starts_with(&#disc) {
return #name::try_from_slice(&value[#disc_len..])
return #name::try_deserialize_unchecked(&mut &value[..])
.map(Self::#name)
.map_err(Into::into)
}
Expand Down
7 changes: 6 additions & 1 deletion lang/attribute/program/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@ pub fn declare_program(input: proc_macro::TokenStream) -> proc_macro::TokenStrea
/// }
/// ```
#[cfg(feature = "interface-instructions")]
#[deprecated(
since = "0.31.0",
note = "Use `#[instruction(discriminator = <EXPR>)]` instead.
See examples in https://github.com/coral-xyz/anchor/tree/v0.31.0/tests/spl/transfer-hook"
)]
#[proc_macro_attribute]
pub fn interface(
_args: proc_macro::TokenStream,
Expand All @@ -106,7 +111,7 @@ pub fn interface(

/// This attribute is used to override the Anchor defaults of program instructions.
///
/// # Args
/// # Arguments
///
/// - `discriminator`: Override the default 8-byte discriminator
///
Expand Down
2 changes: 1 addition & 1 deletion lang/derive/serde/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ lazy-account = []

[dependencies]
anchor-syn = { path = "../../syn", version = "0.30.1" }
borsh-derive-internal = ">=0.9, <0.11"
borsh-derive-internal = "0.10.3"
proc-macro2 = "1"
syn = { version = "1", features = ["full"] }
quote = "1"
24 changes: 20 additions & 4 deletions lang/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,9 +276,8 @@ pub trait AccountDeserialize: Sized {
pub trait ZeroCopy: Discriminator + Copy + Clone + Zeroable + Pod {}

/// Calculates the data for an instruction invocation, where the data is
/// `Sha256(<namespace>:<method_name>)[..8] || BorshSerialize(args)`.
/// `args` is a borsh serialized struct of named fields for each argument given
/// to an instruction.
/// `Discriminator + BorshSerialize(args)`. `args` is a borsh serialized
/// struct of named fields for each argument given to an instruction.
pub trait InstructionData: Discriminator + AnchorSerialize {
fn data(&self) -> Vec<u8> {
let mut data = Vec::with_capacity(256);
Expand All @@ -303,8 +302,25 @@ pub trait Event: AnchorSerialize + AnchorDeserialize + Discriminator {
fn data(&self) -> Vec<u8>;
}

/// 8 byte unique identifier for a type.
/// Unique identifier for a type.
///
/// This is not a trait you should derive manually, as various Anchor macros already derive it
/// internally.
///
/// Prior to Anchor v0.31, discriminators were always 8 bytes in size. However, starting with Anchor
/// v0.31, it is possible to override the default discriminators, and discriminator length is no
/// longer fixed, which means this trait can also be implemented for non-Anchor programs.
///
/// It's important that the discriminator is always unique for the type you're implementing it
/// for. While the discriminator can be at any length (including zero), the IDL generation does not
/// currently allow empty discriminators for safety and convenience reasons. However, the trait
/// definition still allows empty discriminators because some non-Anchor programs, e.g. the SPL
/// Token program, don't have account discriminators. In that case, safety checks should never
/// depend on the discriminator.
pub trait Discriminator {
/// Discriminator slice.
///
/// See [`Discriminator`] trait documentation for more information.
const DISCRIMINATOR: &'static [u8];
}

Expand Down
17 changes: 6 additions & 11 deletions lang/syn/src/codegen/program/dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,19 +61,14 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
quote! {
/// Performs method dispatch.
///
/// Each method in an anchor program is uniquely defined by a namespace
/// and a rust identifier (i.e., the name given to the method). These
/// two pieces can be combined to create a method identifier,
/// specifically, Anchor uses
/// Each instruction's discriminator is checked until the given instruction data starts with
/// the current discriminator.
///
/// Sha256("<namespace>:<rust-identifier>")[..8],
/// If a match is found, the instruction handler is called using the given instruction data
/// excluding the prepended discriminator bytes.
///
/// where the namespace can be one type. "global" for a
/// regular instruction.
///
/// With this 8 byte identifier, Anchor performs method dispatch,
/// matching the given 8 byte identifier to the associated method
/// handler, which leads to user defined code being eventually invoked.
/// If no match is found, the fallback function is executed if it exists, or an error is
/// returned if it doesn't exist.
fn dispatch<'info>(
program_id: &Pubkey,
accounts: &'info [AccountInfo<'info>],
Expand Down
15 changes: 4 additions & 11 deletions lang/syn/src/codegen/program/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,10 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
/// The execution flow of the generated code can be roughly outlined:
///
/// * Start program via the entrypoint.
/// * Strip method identifier off the first 8 bytes of the instruction
/// data and invoke the identified method. The method identifier
/// is a variant of sighash. See docs.rs for `anchor_lang` for details.
/// * If the method identifier is an IDL identifier, execute the IDL
/// instructions, which are a special set of hardcoded instructions
/// baked into every Anchor program. Then exit.
/// * Otherwise, the method identifier is for a user defined
/// instruction, i.e., one of the methods in the user defined
/// `#[program]` module. Perform method dispatch, i.e., execute the
/// big match statement mapping method identifier to method handler
/// wrapper.
/// * Check whether the declared program id matches the input program
/// id. If it's not, return an error.
/// * Find and invoke the method based on whether the instruction data
/// starts with the method's discriminator.
/// * Run the method handler wrapper. This wraps the code the user
/// actually wrote, deserializing the accounts, constructing the
/// context, invoking the user's code, and finally running the exit
Expand Down
20 changes: 19 additions & 1 deletion lang/syn/src/idl/accounts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,25 @@ fn get_address(acc: &Field) -> TokenStream {
.address
.as_ref()
.map(|constraint| &constraint.address)
.filter(|address| !matches!(address, syn::Expr::Field(_)))
.filter(|address| {
match address {
// Allow constants (assume the identifier follows the Rust naming convention)
// e.g. `crate::ID`
syn::Expr::Path(expr) => expr
.path
.segments
.last()
.unwrap()
.ident
.to_string()
.chars()
.all(|c| c.is_uppercase() || c == '_'),
// Allow `const fn`s (assume any stand-alone function call without an argument)
// e.g. `crate::id()`
syn::Expr::Call(expr) => expr.args.is_empty(),
_ => false,
}
})
.map(|address| quote! { Some(#address.to_string()) })
.unwrap_or_else(|| quote! { None }),
}
Expand Down
4 changes: 1 addition & 3 deletions lang/syn/src/idl/defined.rs
Original file line number Diff line number Diff line change
Expand Up @@ -497,9 +497,7 @@ pub fn gen_idl_type(
use quote::ToTokens;

let source_path = proc_macro2::Span::call_site().source_file().path();
let lib_path = find_path("lib.rs", &source_path).expect("lib.rs should exist");

if let Ok(ctx) = CrateContext::parse(lib_path) {
if let Ok(Ok(ctx)) = find_path("lib.rs", &source_path).map(CrateContext::parse) {
let name = path.path.segments.last().unwrap().ident.to_string();
let alias = ctx.type_aliases().find(|ty| ty.ident == name);
if let Some(alias) = alias {
Expand Down
2 changes: 1 addition & 1 deletion spl/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ token_2022_extensions = ["spl-token-2022", "spl-token-group-interface", "spl-tok

[dependencies]
anchor-lang = { path = "../lang", version = "0.30.1", features = ["derive"] }
borsh = { version = ">=0.9, <0.11", optional = true }
borsh = { version = "0.10.3", optional = true }
mpl-token-metadata = { version = "4", optional = true }
serum_dex = { git = "https://github.com/openbook-dex/program/", rev = "1be91f2", version = "0.4.0", features = ["no-entrypoint"], optional = true }
spl-associated-token-account = { version = "3", features = ["no-entrypoint"], optional = true }
Expand Down
13 changes: 13 additions & 0 deletions tests/pda-derivation/programs/pda-derivation/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ pub mod pda_derivation {
pub fn seed_math_expr(_ctx: Context<SeedMathExpr>) -> Result<()> {
Ok(())
}

pub fn resolution_error(_ctx: Context<ResolutionError>) -> Result<()> {
Ok(())
}
}

#[derive(Accounts)]
Expand Down Expand Up @@ -178,6 +182,15 @@ pub struct SeedMathExpr<'info> {
pub math_expr_account: UncheckedAccount<'info>,
}

#[derive(Accounts)]
pub struct ResolutionError<'info> {
pub unknown: UncheckedAccount<'info>,
#[account(seeds = [unknown.key.as_ref()], bump)]
pub pda: UncheckedAccount<'info>,
#[account(seeds = [pda.key.as_ref()], bump)]
pub another_pda: UncheckedAccount<'info>,
}

#[account]
pub struct MyAccount {
data: u64,
Expand Down
13 changes: 13 additions & 0 deletions tests/pda-derivation/tests/typescript.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,17 @@ describe("typescript", () => {
it("Can use unsupported expressions", () => {
// Compilation test to fix issues like https://github.com/coral-xyz/anchor/issues/2933
});

it("Includes the unresolved accounts if resolution fails", async () => {
try {
// `unknown` account is required for account resolution to work, but it's
// intentionally not provided to test the error message
await program.methods.resolutionError().rpc();
throw new Error("Should throw due to account resolution failure!");
} catch (e) {
expect(e.message).to.equal(
"Reached maximum depth for account resolution. Unresolved accounts: `pda`, `anotherPda`"
);
}
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub mod relations_derivation {
Ok(())
}

pub fn test_address_relation(_ctx: Context<TestAddressRelation>) -> Result<()> {
pub fn test_address(_ctx: Context<TestAddress>) -> Result<()> {
Ok(())
}
}
Expand Down Expand Up @@ -66,9 +66,20 @@ pub struct TestRelation<'info> {
}

#[derive(Accounts)]
pub struct TestAddressRelation<'info> {
pub struct TestAddress<'info> {
// Included wit the `address` field in IDL
// It's actually `static` but it doesn't matter for our purposes
#[account(address = crate::ID)]
constant: UncheckedAccount<'info>,
#[account(address = crate::id())]
const_fn: UncheckedAccount<'info>,

// Not included with the `address` field in IDL
#[account(address = my_account.my_account)]
account: UncheckedAccount<'info>,
field: UncheckedAccount<'info>,
#[account(address = my_account.my_account())]
method: UncheckedAccount<'info>,

#[account(seeds = [b"seed"], bump = my_account.bump)]
my_account: Account<'info, MyAccount>,
}
Expand All @@ -78,3 +89,9 @@ pub struct MyAccount {
pub my_account: Pubkey,
pub bump: u8,
}

impl MyAccount {
pub fn my_account(&self) -> Pubkey {
self.my_account
}
}
11 changes: 8 additions & 3 deletions tests/relations-derivation/tests/typescript.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,13 @@ describe("typescript", () => {
await tx.rpc();
});

it("Can use relations derivation with `address` constraint", () => {
// Only compile test for now since the IDL spec doesn't currently support field access
// expressions for the `address` constraint
it("Can use `address` constraint", () => {
const ix = program.idl.instructions.find(
(ix) => ix.name === "testAddress"
)!;
expect(ix.accounts.find((acc) => acc.name === "constant")!.address).to.not
.be.undefined;
expect(ix.accounts.find((acc) => acc.name === "constFn")!.address).to.not.be
.undefined;
});
});
Loading

0 comments on commit 92cdf0a

Please sign in to comment.