0.31.0
Anchor - Release Notes 0.31.0
The last major release before v1 is finally here.
As always, there are a great number of changes, but we'll only be covering the most important ones here. For a list of all notable changes, see the CHANGELOG.
How to upgrade
-
Install the latest version of
avm
:This will allow installing Anchor CLI without having to compile from source, see Install from binary.
-
Update
anchor-cli
: -
Update Anchor crate(s) to
0.31.0
. -
Update TS package(s) to
0.31.0
.
Recommended Solana Version
The recommended Solana version is 2.1.0
. This is a special upgrade because
some of the Solana binaries have been renamed to Agave, see
Agave transition.
You can install the newer tooling by running:
This change is handled automatically if you specify toolchain.solana_version
,
see Automatic Agave transition.
AVM
Install from binary
avm install
now downloads binaries from GitHub by default.
The following build targets are supported:
aarch64-apple-darwin
x86_64-unknown-linux-gnu
x86_64-apple-darwin
x86_64-pc-windows-msvc
You can add the --from-source
flag to the install
command if that's
preferred (or required due to unsupported platform).
CLI
Automatic Agave transition
As mentioned in Recommended Solana version
section, some of the Solana binaries are renamed to Agave. solana-install
is
deprecated in 1.18.19
and logs a deprecation message when used (this results
in parsing failure in older Anchor versions):
In this release, if you specify solana_version
field with a version greater
than 1.18.19
, it automatically installs and switches to agave-install
:
solana-program
warning
Adding solana-program
as a dependency of Anchor programs should be avoided to
decrease the possibility of version conflicts between Solana v1 and v2 crates.
You'll see the following warning on builds if you have solana-program
in your
dependency list:
Pass cargo
args to IDL build
Both anchor build
and anchor idl build
commands pass the cargo
arguments
to the underyling IDL build command. For example:
now builds the IDL with my-feature
enabled.
--no-idl
flag for tests
If you make a change to your program, but the API of the program stays the same, building the IDL is pointless and takes additional time.
Similar to --no-idl
flag on builds, now you
can use:
mollusk
test template
You can initialize your workspace using the new
mollusk
template by running:
clean
anchor clean
now also removes the generated .anchor
directory.
For those of you that don't know, this command is similar to cargo clean
, but
it keeps the program keypairs.
Automatic IDL conversion
Legacy IDLs (pre Anchor v0.30) were not supported in v0.30, unless you first
converted them to the new spec using anchor idl convert
. In this release,
various commands do this conversion automatically, meaning you'll be able to
work with both specs without having to switch versions. The only exception is
the idl fetch
command, which does not convert legacy IDLs.
Shell completions
You can now generate shell completions, see Generating Shell Completions.
Lang
Stack memory improvements
This is going to be a longer section, TL;DR is stack usage is improved massively
when using init
constraints, and stack warnings on builds are now reliable
when using Solana v2 (platform-tools v1.42
). Keep reading if you're interested
in learning more, otherwise you can skip to
Custom discriminators.
The main place where Anchor programs are likely to hit stack violation errors is
a generated function called try_accounts
. This is where the instruction is
deserialized and constraints are run. Although having everything at the same
place is convenient for using constraints, this also makes it very easy to use
the fixed amount of stack space (4096 bytes) SVM allocates just by increasing
the number of accounts the instruction has. You might be familiar with it from
the mangled build logs:
The problem was made worse with the following external developments:
- Rust/LLVM changes shipped with Solana v1.18 made Anchor's
try_accounts
function use even more stack space, resulting in much lower threshold to hit stack-related problems. - The stack logs were unreliable, meaning you wouldn't always get warnings during builds if you went over the stack limit.
- The feature "Account data direct mapping", which is enabled by default when using local-validator, made the programs run into undefined behavior when a function used more stack space than it had available.
All of this combined meant that your programs used more stack space (1), but sometimes the errors didn't get caught during the compile time (2) or even the runtime (3).
Undefined behavior is particularly challenging to debug because things may appear to work as expected during tests, but a different input to the same test might overwrite an account's data with unintended bytes. There are endless scenarios that could go wrong here, and some examples include #2955, #3113, and #3196.
There isn't much we can do for problems 1 and 3, but the problem 2 is resolved
with Solana v2 (platform-tools v1.42
), meaning you'll reliably get warnings
about all stack problems.
Circling back to Anchor, the biggest offender to the stack usage was identified
to be the init
constraint. Each init
constraint expands to a lengthy code
inside try_accounts
, resulting in excessive stack usage when multiple init
constraints are used. This problem was fixed by moving the init
code inside a
closure and immediately calling it in order to create and use a different stack
frame (#2939).
Related to this topic, there is SIMD-0166, a proposal to introduce dynamic stack frames.
In short, you'll have fewer problems related to stack memory when using Anchor v0.31 and Solana v2. If you're still running into problems, please create an issue in coral-xyz/anchor.
Custom discriminators
Before this release, there were several problems regarding Anchor discriminators:
- Due to the transaction size limits enforced by the Solana runtime (1232 bytes), 8 bytes can be too high for some use cases
- The
Discriminator
trait had a fixed size type field ([u8; 8]
), which meant we wouldn't be able to implement it for non-Anchor programs (e.g. indeclare_program!
) - Discriminators were not customizable
- Changing the name of the data type the discriminator was derived from resulted in a different discriminator
This release solves all of the above problems by introducing support for custom
discriminators. The default 8-byte discriminators have not changed, but you can
override them via the discriminator
argument implemented in various Anchor
attribute macros:
#[account(discriminator = 1)]
#[event(discriminator = [1, 2])]
#[instruction(discriminator = MY_CONST)]
All constant expressions are supported.
See example.
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 Discriminator
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.
Additionally, the IDL generation step also checks whether you have ambigious
discriminators i.e. discriminators that can be used for multiple types. However,
you should still consider future possibilities, especially when working with
1-byte discriminators. For example, having an account with discriminator [1]
means you can't have any other discriminators that start with 1
, e.g.
[1, 2 , 3, 4]
, as it would not be unique.
This change also enables using non-Anchor programs with both Rust (via
declare_program!
) and in the
TS client.
Discriminator
trait
The discriminator
method of the Discriminator
trait has been removed. If you
have compilation errors related to this removal, you can simply replace the
discriminator()
call to the DISCRIMINATOR
associated constant.
This trait is now exported from prelude
, and it can be used to replace a very
common usage that hardcodes the discriminator length as 8
. For example, the
following:
can be replaced by:
LazyAccount
LazyAccount
is an experimental account type that can be used to replace
Account
when you're running into performance-related problems.
We'll skip the details to keep the release notes as short as possible, but if you're interested, check out its documentation to see if it fits your needs.
Note: You need to enable lazy-account
feature of anchor-lang
to be able
to use LazyAccount
.
cfg
attribute on instructions
You can now use cfg
attributes on instructions:
Unnamed and unit structs with InitSpace
Unnamed and unit struct support was added in v0.30, but deriving InitSpace
did
not work with these structs. This release adds support for both of them:
Account parser
You can now conveniently parse any program account using declare_program!
:
This will generate something similar to:
Use my_program::utils::Account::try_from_bytes
to parse any account belonging
to the program.
declare_program!
improvements
The following issues related to
declare_program!
have been fixed:
- Being unable to use constant bytes (#3287)
- Missing docs from the generated constants (#3311)
- Compilation errors related to incorrectly adding
derive
s andrepr
s to type aliases (#3504) - Being unable to use
data
as an instruction parameter (#3574)
SPL
New Token 2022 instructions
The following Token 2022 instructions were added:
burn_checked
mint_to_checked
approve_checked
withdraw_withheld_tokens_from_accounts
IDL
Safety comment checks
In v0.30.1, you'd run into panics in Rust Analyzer if you enabled all features
because the idl-build
feature expected an environment variable to be set. This
was always set if you used anchor build
, but since Rust Analyzer did not know
about this environment variable, it would panic:
It no longer panics if the environment variable is missing.
address
constraint with non-const expressions
There was a regression in v0.30 that made using non-const expressions with the
address
constraint fail:
This is now fixed and no longer results in build errors.
See coral-xyz/anchor#3216 for more information.
Program
accounts with full paths
The following did not work in v0.30, but it works now:
IdlBuilder
Building the IDL via the
build_idl
function made it impossible to extend its functionality e.g. add new parameters
without a breaking change. To solve this problem, there is a new way to build
IDLs programatically:
See
IdlBuilder
for more information.
Generation improvements
The following issues with the IDL generation have been fixed:
- A bug where using tuple parameters in instructions would result in an incorrect IDL (#3294)
- A bug where doc comments could trigger false-positives during module paths convertion (#3359)
- A bug where the generated IDL only has partial resolution information (#3474)
- Being unable to use constant identifiers as generic arguments (#3522)
- Being unable to pass in a
Pubkey
constant toseeds::program
(#3559) - Being unable to pass in an account or an argument to
seeds::program
(#3570)
TypeScript
Simpler Program
construction
TypeScript's automatic inference of JSON files made it difficult to use the
Program
constructor without additional casting:
Casting to unknown
or any
was necessary when TypeScript automatically
inferred the type of the JSON file.
In this release, the program constructor no longer infers the IDL type from the
given idl
argument. This makes it easier to specify the actual IDL type:
Error improvements
Account resolution error now includes the accounts that weren't able to get resolved:
Similarly, unsupported view
method error now includes the possible causes:
Type improvements
It's common to use //@ts-ignore
to get the payer keypair in tests:
To fix this problem, the Provider
interface now includes an optional
wallet: Wallet
field, and similarly, the Wallet
interface now includes
optional payer: Keypair
field.
You can now do:
We're using !
because we know these fields are going to be defined in our
testing environment.
Better confirmation
Provider.sendAndConfirm
now takes in an optional blockhash
and uses that for
better transaction confirmation:
Programs with numbers in their name
Testing programs with numbers in their name using anchor.workspace
now works
for all cases.
For more details about the problem and its solution, see #3450.
Rust Client
tokio
support
There was a problem that made it impossible to use tokio
with
anchor-client
.
This problem is now fixed, and you can use tokio
(with async
feature). See
tokio
example.
Mock client
It's now possible to pass in a
mock RPC client
for testing by enabling the mock
feature:
See the full list of notable changes in the CHANGELOG.