adapt book to error rework (#14)
This commit is contained in:
parent
b992f4828b
commit
beeebca7af
|
@ -7,23 +7,25 @@ The autogenerated clients can automatically parse Anchor Internal Errors and Cus
|
|||
|
||||
## Anchor Internal Errors
|
||||
|
||||
> [Anchor Internal Error Code Reference](https://docs.rs/anchor-lang/latest/anchor_lang/__private/enum.ErrorCode.html)
|
||||
> [Anchor Internal Error Code Reference](https://docs.rs/anchor-lang/latest/anchor_lang/error/enum.ErrorCode.html)
|
||||
|
||||
Anchor has many different internal error codes. These are not meant to be used by users, but it's useful to study the reference to learn about the mappings between codes and their causes. They are, for example, thrown when a constraint has been violated, e.g. when an account is marked with `mut` but its `is_writable` property is `false`.
|
||||
|
||||
## Custom Errors
|
||||
|
||||
You can add errors that are unique to your program by using the error attribute.
|
||||
You can add errors that are unique to your program by using the `error_code` attribute.
|
||||
|
||||
Simply add it to an enum with a name of your choice. You can then use the variants of the enum as errors in your program. Additionally, you can add a message attribute to the individual variants. Clients will then display this error message if the error occurs. Custom Error code numbers start at the [custom error offset](https://docs.rs/anchor-lang/latest/anchor_lang/__private/constant.ERROR_CODE_OFFSET.html).
|
||||
Simply add it to an enum with a name of your choice. You can then use the variants of the enum as errors in your program. Additionally, you can add a message attribute to the individual variants. Clients will then display this error message if the error occurs. Custom Error code numbers start at the [custom error offset](https://docs.rs/anchor-lang/latest/anchor_lang/error/constant.ERROR_CODE_OFFSET.html).
|
||||
|
||||
To actually throw an error use the [`err!`](https://docs.rs/anchor-lang/latest/anchor_lang/macro.err.html) or the [`error!`](https://docs.rs/anchor-lang/latest/anchor_lang/prelude/macro.error.html) macro. These add file and line information to the error that is then logged by anchor.
|
||||
|
||||
```rust,ignore
|
||||
#[program]
|
||||
mod hello_anchor {
|
||||
use super::*;
|
||||
pub fn set_data(ctx: Context<SetData>, data: MyAccount) -> ProgramResult {
|
||||
pub fn set_data(ctx: Context<SetData>, data: MyAccount) -> Result<()> {
|
||||
if data.data >= 100 {
|
||||
return Err(MyError::DataTooLarge.into());
|
||||
return err!(MyError::DataTooLarge);
|
||||
}
|
||||
ctx.accounts.my_account.set_inner(data);
|
||||
Ok(())
|
||||
|
@ -31,19 +33,21 @@ mod hello_anchor {
|
|||
}
|
||||
|
||||
|
||||
#[error]
|
||||
#[error_code]
|
||||
pub enum MyError {
|
||||
#[msg("MyAccount may only hold data below 100")]
|
||||
DataTooLarge
|
||||
}
|
||||
```
|
||||
|
||||
### require!
|
||||
|
||||
You can use the [`require`](https://docs.rs/anchor-lang/latest/anchor_lang/macro.require.html) macro to simplify writing errors. The code above can be simplified to this (Note that the `>=` flips to `<`):
|
||||
```rust,ignore
|
||||
#[program]
|
||||
mod hello_anchor {
|
||||
use super::*;
|
||||
pub fn set_data(ctx: Context<SetData>, data: MyAccount) -> ProgramResult {
|
||||
pub fn set_data(ctx: Context<SetData>, data: MyAccount) -> Result<()> {
|
||||
require!(data.data < 100, MyError::DataTooLarge);
|
||||
ctx.accounts.my_account.set_inner(data);
|
||||
Ok(())
|
||||
|
@ -51,7 +55,7 @@ mod hello_anchor {
|
|||
}
|
||||
|
||||
|
||||
#[error]
|
||||
#[error_code]
|
||||
pub enum MyError {
|
||||
#[msg("MyAccount may only hold data below 100")]
|
||||
DataTooLarge
|
||||
|
|
|
@ -13,7 +13,7 @@ declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
|
|||
#[program]
|
||||
mod hello_anchor {
|
||||
use super::*;
|
||||
pub fn initialize(_ctx: Context<Initialize>) -> ProgramResult {
|
||||
pub fn initialize(_ctx: Context<Initialize>) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -109,7 +109,7 @@ And with this, `SetupGame` is complete and we can move on to the `setup_game` fu
|
|||
|
||||
Let's start by adding an argument to the `setup_game` function.
|
||||
```rust,ignore
|
||||
pub fn setup_game(ctx: Context<SetupGame>, player_two: Pubkey) -> ProgramResult {
|
||||
pub fn setup_game(ctx: Context<SetupGame>, player_two: Pubkey) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
@ -117,7 +117,7 @@ Why didn't we just add `player_two` as an account in the accounts struct? There
|
|||
|
||||
Finish the instruction function by setting the game to its initial values:
|
||||
```rust,ignore
|
||||
pub fn setup_game(ctx: Context<SetupGame>, player_two: Pubkey) -> ProgramResult {
|
||||
pub fn setup_game(ctx: Context<SetupGame>, player_two: Pubkey) -> Result<()> {
|
||||
let game = &mut ctx.accounts.game;
|
||||
game.players = [ctx.accounts.player_one.key(), player_two];
|
||||
game.turn = 1;
|
||||
|
@ -202,9 +202,9 @@ impl Game {
|
|||
self.players[self.current_player_index()]
|
||||
}
|
||||
|
||||
pub fn play(&mut self, tile: &Tile) -> ProgramResult {
|
||||
pub fn play(&mut self, tile: &Tile) -> Result<()> {
|
||||
if !self.is_active() {
|
||||
return Err(TicTacToeError::GameAlreadyOver.into());
|
||||
return err!(TicTacToeError::GameAlreadyOver);
|
||||
}
|
||||
match tile {
|
||||
tile
|
||||
|
@ -212,13 +212,13 @@ impl Game {
|
|||
row: 0..=2,
|
||||
column: 0..=2,
|
||||
} => match self.board[tile.row as usize][tile.column as usize] {
|
||||
Some(_) => return Err(TicTacToeError::TileAlreadySet.into()),
|
||||
Some(_) => return err!(TicTacToeError::TileAlreadySet),
|
||||
None => {
|
||||
self.board[tile.row as usize][tile.column as usize] =
|
||||
Some(Sign::from_usize(self.current_player_index()).unwrap());
|
||||
}
|
||||
},
|
||||
_ => return Err(TicTacToeError::TileOutOfBounds.into()),
|
||||
_ => return err!(TicTacToeError::TileOutOfBounds),
|
||||
}
|
||||
|
||||
self.update_state();
|
||||
|
@ -302,7 +302,7 @@ pub struct Tile {
|
|||
|
||||
and the `TicTacToeError` type.
|
||||
```rust,ignore
|
||||
#[error]
|
||||
#[error_code]
|
||||
pub enum TicTacToeError {
|
||||
TileOutOfBounds,
|
||||
TileAlreadySet,
|
||||
|
@ -313,7 +313,7 @@ pub enum TicTacToeError {
|
|||
|
||||
Finally, we can add the `play` function inside the program module.
|
||||
```rust,ignore
|
||||
pub fn play(ctx: Context<Play>, tile: Tile) -> ProgramResult {
|
||||
pub fn play(ctx: Context<Play>, tile: Tile) -> Result<()> {
|
||||
let game = &mut ctx.accounts.game;
|
||||
|
||||
require!(
|
||||
|
|
|
@ -22,7 +22,7 @@ declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
|
|||
#[program]
|
||||
mod hello_anchor {
|
||||
use super::*;
|
||||
pub fn set_data(ctx: Context<SetData>, data: u64) -> ProgramResult {
|
||||
pub fn set_data(ctx: Context<SetData>, data: u64) -> Result<()> {
|
||||
ctx.accounts.my_account.data = data;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
|
|||
#[program]
|
||||
mod hello_anchor {
|
||||
use super::*;
|
||||
pub fn set_data(ctx: Context<SetData>, data: u64) -> ProgramResult {
|
||||
pub fn set_data(ctx: Context<SetData>, data: u64) -> Result<()> {
|
||||
if ctx.accounts.token_account.amount > 0 {
|
||||
ctx.accounts.my_account.data = data;
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ The program module is where you define your business logic. You do so by writing
|
|||
#[program]
|
||||
mod hello_anchor {
|
||||
use super::*;
|
||||
pub fn set_data(ctx: Context<SetData>, data: u64) -> ProgramResult {
|
||||
pub fn set_data(ctx: Context<SetData>, data: u64) -> Result<()> {
|
||||
if ctx.accounts.token_account.amount > 0 {
|
||||
ctx.accounts.my_account.data = data;
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ If your function requires instruction data, you can add it by adding arguments t
|
|||
#[program]
|
||||
mod hello_anchor {
|
||||
use super::*;
|
||||
pub fn set_data(ctx: Context<SetData>, data: Data) -> ProgramResult {
|
||||
pub fn set_data(ctx: Context<SetData>, data: Data) -> Result<()> {
|
||||
ctx.accounts.my_account.data = data.data;
|
||||
ctx.accounts.my_account.age = data.age;
|
||||
Ok(())
|
||||
|
@ -61,7 +61,7 @@ Conveniently, `#[account]` implements `Anchor(De)Serialize` for `MyAccount`, so
|
|||
#[program]
|
||||
mod hello_anchor {
|
||||
use super::*;
|
||||
pub fn set_data(ctx: Context<SetData>, data: MyAccount) -> ProgramResult {
|
||||
pub fn set_data(ctx: Context<SetData>, data: MyAccount) -> Result<()> {
|
||||
ctx.accounts.my_account.set_inner(data);
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue