lang: Remove belongs_to in favor of has_one (#459)
This commit is contained in:
parent
6c44ca94d7
commit
2d974604ae
|
@ -19,6 +19,7 @@ incremented for features.
|
|||
### Breaking Changes
|
||||
|
||||
* cli: Remove `.spec` suffix on TypeScript tests files ([#441](https://github.com/project-serum/anchor/pull/441)).
|
||||
* lang: Remove `belongs_to` constraint ([#459](https://github.com/project-serum/anchor/pull/459)).
|
||||
|
||||
## [0.10.0] - 2021-06-27
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit a6c389d6ece753d83bff1cff38d315775fefb467
|
||||
Subproject commit a72e59a9b263b7e083af737669f12f5e3ee1997c
|
|
@ -23,7 +23,7 @@ mod errors {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn belongs_to_error(_ctx: Context<BelongsToError>) -> Result<()> {
|
||||
pub fn has_one_error(_ctx: Context<HasOneError>) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -42,9 +42,9 @@ pub struct MutError<'info> {
|
|||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct BelongsToError<'info> {
|
||||
#[account(init, belongs_to = owner)]
|
||||
my_account: ProgramAccount<'info, BelongsToAccount>,
|
||||
pub struct HasOneError<'info> {
|
||||
#[account(init, has_one = owner)]
|
||||
my_account: ProgramAccount<'info, HasOneAccount>,
|
||||
owner: AccountInfo<'info>,
|
||||
rent: Sysvar<'info, Rent>,
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ pub struct SignerError<'info> {
|
|||
}
|
||||
|
||||
#[account]
|
||||
pub struct BelongsToAccount {
|
||||
pub struct HasOneAccount {
|
||||
owner: Pubkey,
|
||||
}
|
||||
|
||||
|
|
|
@ -61,23 +61,23 @@ describe("errors", () => {
|
|||
}
|
||||
});
|
||||
|
||||
it("Emits a belongs to error", async () => {
|
||||
it("Emits a has one error", async () => {
|
||||
try {
|
||||
const account = new Account();
|
||||
const tx = await program.rpc.belongsToError({
|
||||
const tx = await program.rpc.hasOneError({
|
||||
accounts: {
|
||||
myAccount: account.publicKey,
|
||||
owner: anchor.web3.SYSVAR_RENT_PUBKEY,
|
||||
rent: anchor.web3.SYSVAR_RENT_PUBKEY,
|
||||
},
|
||||
instructions: [
|
||||
await program.account.belongsToAccount.createInstruction(account),
|
||||
await program.account.hasOneAccount.createInstruction(account),
|
||||
],
|
||||
signers: [account],
|
||||
});
|
||||
assert.ok(false);
|
||||
} catch (err) {
|
||||
const errMsg = "A belongs_to constraint was violated";
|
||||
const errMsg = "A has_one constraint was violated";
|
||||
assert.equal(err.toString(), errMsg);
|
||||
assert.equal(err.msg, errMsg);
|
||||
assert.equal(err.code, 141);
|
||||
|
|
|
@ -739,7 +739,7 @@ pub struct DepositLocked<'info> {
|
|||
// Program specific.
|
||||
registry: ProgramState<'info, Registry>,
|
||||
registrar: ProgramAccount<'info, Registrar>,
|
||||
#[account(belongs_to = registrar, has_one = beneficiary)]
|
||||
#[account(has_one = registrar, has_one = beneficiary)]
|
||||
member: ProgramAccount<'info, Member>,
|
||||
#[account(signer)]
|
||||
beneficiary: AccountInfo<'info>,
|
||||
|
@ -755,7 +755,7 @@ pub struct Stake<'info> {
|
|||
pool_mint: CpiAccount<'info, Mint>,
|
||||
|
||||
// Member.
|
||||
#[account(mut, has_one = beneficiary, belongs_to = registrar)]
|
||||
#[account(mut, has_one = beneficiary, has_one = registrar)]
|
||||
member: ProgramAccount<'info, Member>,
|
||||
#[account(signer)]
|
||||
beneficiary: AccountInfo<'info>,
|
||||
|
@ -794,7 +794,7 @@ pub struct StartUnstake<'info> {
|
|||
// Member.
|
||||
#[account(init)]
|
||||
pending_withdrawal: ProgramAccount<'info, PendingWithdrawal>,
|
||||
#[account(has_one = beneficiary, belongs_to = registrar)]
|
||||
#[account(has_one = beneficiary, has_one = registrar)]
|
||||
member: ProgramAccount<'info, Member>,
|
||||
#[account(signer)]
|
||||
beneficiary: AccountInfo<'info>,
|
||||
|
@ -824,11 +824,11 @@ pub struct StartUnstake<'info> {
|
|||
pub struct EndUnstake<'info> {
|
||||
registrar: ProgramAccount<'info, Registrar>,
|
||||
|
||||
#[account(belongs_to = registrar, has_one = beneficiary)]
|
||||
#[account(has_one = registrar, has_one = beneficiary)]
|
||||
member: ProgramAccount<'info, Member>,
|
||||
#[account(signer)]
|
||||
beneficiary: AccountInfo<'info>,
|
||||
#[account(mut, belongs_to = registrar, belongs_to = member, "!pending_withdrawal.burned")]
|
||||
#[account(mut, has_one = registrar, has_one = member, "!pending_withdrawal.burned")]
|
||||
pending_withdrawal: ProgramAccount<'info, PendingWithdrawal>,
|
||||
|
||||
// If we had ordered maps implementing Accounts we could do a constraint like
|
||||
|
@ -859,7 +859,7 @@ pub struct Withdraw<'info> {
|
|||
// Stake instance.
|
||||
registrar: ProgramAccount<'info, Registrar>,
|
||||
// Member.
|
||||
#[account(belongs_to = registrar, has_one = beneficiary)]
|
||||
#[account(has_one = registrar, has_one = beneficiary)]
|
||||
member: ProgramAccount<'info, Member>,
|
||||
#[account(signer)]
|
||||
beneficiary: AccountInfo<'info>,
|
||||
|
@ -912,7 +912,7 @@ pub struct WithdrawLocked<'info> {
|
|||
// Program specific.
|
||||
registry: ProgramState<'info, Registry>,
|
||||
registrar: ProgramAccount<'info, Registrar>,
|
||||
#[account(belongs_to = registrar, has_one = beneficiary)]
|
||||
#[account(has_one = registrar, has_one = beneficiary)]
|
||||
member: ProgramAccount<'info, Member>,
|
||||
#[account(signer)]
|
||||
beneficiary: AccountInfo<'info>,
|
||||
|
@ -984,7 +984,7 @@ pub struct ClaimRewardCommon<'info> {
|
|||
// Stake instance.
|
||||
registrar: ProgramAccount<'info, Registrar>,
|
||||
// Member.
|
||||
#[account(mut, belongs_to = registrar, has_one = beneficiary)]
|
||||
#[account(mut, has_one = registrar, has_one = beneficiary)]
|
||||
member: ProgramAccount<'info, Member>,
|
||||
#[account(signer)]
|
||||
beneficiary: AccountInfo<'info>,
|
||||
|
@ -993,7 +993,7 @@ pub struct ClaimRewardCommon<'info> {
|
|||
#[account("BalanceSandbox::from(&balances_locked) == member.balances_locked")]
|
||||
balances_locked: BalanceSandboxAccounts<'info>,
|
||||
// Vendor.
|
||||
#[account(belongs_to = registrar, has_one = vault)]
|
||||
#[account(has_one = registrar, has_one = vault)]
|
||||
vendor: ProgramAccount<'info, RewardVendor>,
|
||||
#[account(mut)]
|
||||
vault: AccountInfo<'info>,
|
||||
|
@ -1016,7 +1016,7 @@ pub struct ExpireReward<'info> {
|
|||
// Staking instance globals.
|
||||
registrar: ProgramAccount<'info, Registrar>,
|
||||
// Vendor.
|
||||
#[account(mut, belongs_to = registrar, has_one = vault, has_one = expiry_receiver)]
|
||||
#[account(mut, has_one = registrar, has_one = vault, has_one = expiry_receiver)]
|
||||
vendor: ProgramAccount<'info, RewardVendor>,
|
||||
#[account(mut)]
|
||||
vault: CpiAccount<'info, TokenAccount>,
|
||||
|
|
|
@ -183,7 +183,7 @@ pub struct CreateTransaction<'info> {
|
|||
#[derive(Accounts)]
|
||||
pub struct Approve<'info> {
|
||||
multisig: ProgramAccount<'info, Multisig>,
|
||||
#[account(mut, belongs_to = multisig)]
|
||||
#[account(mut, has_one = multisig)]
|
||||
transaction: ProgramAccount<'info, Transaction>,
|
||||
// One of the multisig owners. Checked in the handler.
|
||||
#[account(signer)]
|
||||
|
@ -209,7 +209,7 @@ pub struct ExecuteTransaction<'info> {
|
|||
&[multisig.nonce],
|
||||
])]
|
||||
multisig_signer: AccountInfo<'info>,
|
||||
#[account(mut, belongs_to = multisig)]
|
||||
#[account(mut, has_one = multisig)]
|
||||
transaction: ProgramAccount<'info, Transaction>,
|
||||
}
|
||||
|
||||
|
|
|
@ -41,8 +41,7 @@ use syn::parse_macro_input;
|
|||
/// | `#[account(mut)]` | On `AccountInfo`, `ProgramAccount` or `CpiAccount` structs. | Marks the account as mutable and persists the state transition. |
|
||||
/// | `#[account(init)]` | On `ProgramAccount` structs. | Marks the account as being initialized, skipping the account discriminator check. When using `init`, a `rent` `Sysvar` must be present in the `Accounts` struct. |
|
||||
/// | `#[account(close = <target>)]` | On `ProgramAccount` and `Loader` structs. | Marks the account as being closed at the end of the instruction's execution, sending the rent exemption lamports to the specified <target>. |
|
||||
/// | `#[account(belongs_to = <target>)]` | On `ProgramAccount` or `CpiAccount` structs | Checks the `target` field on the account matches the `target` field in the struct deriving `Accounts`. |
|
||||
/// | `#[account(has_one = <target>)]` | On `ProgramAccount` or `CpiAccount` structs | Semantically different, but otherwise the same as `belongs_to`. |
|
||||
/// | `#[account(has_one = <target>)]` | On `ProgramAccount` or `CpiAccount` structs | Checks the `target` field on the account matches the `target` field in the struct deriving `Accounts`. |
|
||||
/// | `#[account(seeds = [<seeds>])]` | On `AccountInfo` structs | Seeds for the program derived address an `AccountInfo` struct represents. |
|
||||
/// | `#[account(constraint = <expression>)]` | On any type deriving `Accounts` | Executes the given code as a constraint. The expression should evaluate to a boolean. |
|
||||
/// | `#[account("<literal>")]` | Deprecated | Executes the given code literal as a constraint. The literal should evaluate to a boolean. |
|
||||
|
|
|
@ -22,8 +22,8 @@ pub enum ErrorCode {
|
|||
// Constraints.
|
||||
#[msg("A mut constraint was violated")]
|
||||
ConstraintMut = 140,
|
||||
#[msg("A belongs to constraint was violated")]
|
||||
ConstraintBelongsTo,
|
||||
#[msg("A has one constraint was violated")]
|
||||
ConstraintHasOne,
|
||||
#[msg("A signer constraint as violated")]
|
||||
ConstraintSigner,
|
||||
#[msg("A raw constraint was violated")]
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{
|
||||
CompositeField, Constraint, ConstraintAddress, ConstraintAssociatedGroup, ConstraintBelongsTo,
|
||||
ConstraintClose, ConstraintExecutable, ConstraintGroup, ConstraintInit, ConstraintLiteral,
|
||||
CompositeField, Constraint, ConstraintAddress, ConstraintAssociatedGroup, ConstraintClose,
|
||||
ConstraintExecutable, ConstraintGroup, ConstraintHasOne, ConstraintInit, ConstraintLiteral,
|
||||
ConstraintMut, ConstraintOwner, ConstraintRaw, ConstraintRentExempt, ConstraintSeedsGroup,
|
||||
ConstraintSigner, ConstraintState, Field, PdaKind, Ty,
|
||||
};
|
||||
|
@ -43,7 +43,7 @@ pub fn linearize(c_group: &ConstraintGroup) -> Vec<Constraint> {
|
|||
init,
|
||||
mutable,
|
||||
signer,
|
||||
belongs_to,
|
||||
has_one,
|
||||
literal,
|
||||
raw,
|
||||
owner,
|
||||
|
@ -73,7 +73,7 @@ pub fn linearize(c_group: &ConstraintGroup) -> Vec<Constraint> {
|
|||
if let Some(c) = signer {
|
||||
constraints.push(Constraint::Signer(c));
|
||||
}
|
||||
constraints.append(&mut belongs_to.into_iter().map(Constraint::BelongsTo).collect());
|
||||
constraints.append(&mut has_one.into_iter().map(Constraint::HasOne).collect());
|
||||
constraints.append(&mut literal.into_iter().map(Constraint::Literal).collect());
|
||||
constraints.append(&mut raw.into_iter().map(Constraint::Raw).collect());
|
||||
if let Some(c) = owner {
|
||||
|
@ -101,7 +101,7 @@ fn generate_constraint(f: &Field, c: &Constraint) -> proc_macro2::TokenStream {
|
|||
match c {
|
||||
Constraint::Init(c) => generate_constraint_init(f, c),
|
||||
Constraint::Mut(c) => generate_constraint_mut(f, c),
|
||||
Constraint::BelongsTo(c) => generate_constraint_belongs_to(f, c),
|
||||
Constraint::HasOne(c) => generate_constraint_has_one(f, c),
|
||||
Constraint::Signer(c) => generate_constraint_signer(f, c),
|
||||
Constraint::Literal(c) => generate_constraint_literal(c),
|
||||
Constraint::Raw(c) => generate_constraint_raw(c),
|
||||
|
@ -157,10 +157,7 @@ pub fn generate_constraint_mut(f: &Field, _c: &ConstraintMut) -> proc_macro2::To
|
|||
}
|
||||
}
|
||||
|
||||
pub fn generate_constraint_belongs_to(
|
||||
f: &Field,
|
||||
c: &ConstraintBelongsTo,
|
||||
) -> proc_macro2::TokenStream {
|
||||
pub fn generate_constraint_has_one(f: &Field, c: &ConstraintHasOne) -> proc_macro2::TokenStream {
|
||||
let target = c.join_target.clone();
|
||||
let ident = &f.ident;
|
||||
let field = match &f.ty {
|
||||
|
@ -169,7 +166,7 @@ pub fn generate_constraint_belongs_to(
|
|||
};
|
||||
quote! {
|
||||
if &#field.#target != #target.to_account_info().key {
|
||||
return Err(anchor_lang::__private::ErrorCode::ConstraintBelongsTo.into());
|
||||
return Err(anchor_lang::__private::ErrorCode::ConstraintHasOne.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -271,7 +271,7 @@ pub struct ConstraintGroup {
|
|||
executable: Option<ConstraintExecutable>,
|
||||
state: Option<ConstraintState>,
|
||||
associated: Option<ConstraintAssociatedGroup>,
|
||||
belongs_to: Vec<ConstraintBelongsTo>,
|
||||
has_one: Vec<ConstraintHasOne>,
|
||||
literal: Vec<ConstraintLiteral>,
|
||||
raw: Vec<ConstraintRaw>,
|
||||
close: Option<ConstraintClose>,
|
||||
|
@ -305,7 +305,7 @@ pub enum Constraint {
|
|||
Init(ConstraintInit),
|
||||
Mut(ConstraintMut),
|
||||
Signer(ConstraintSigner),
|
||||
BelongsTo(ConstraintBelongsTo),
|
||||
HasOne(ConstraintHasOne),
|
||||
Literal(ConstraintLiteral),
|
||||
Raw(ConstraintRaw),
|
||||
Owner(ConstraintOwner),
|
||||
|
@ -325,7 +325,7 @@ pub enum ConstraintToken {
|
|||
Init(Context<ConstraintInit>),
|
||||
Mut(Context<ConstraintMut>),
|
||||
Signer(Context<ConstraintSigner>),
|
||||
BelongsTo(Context<ConstraintBelongsTo>),
|
||||
HasOne(Context<ConstraintHasOne>),
|
||||
Literal(Context<ConstraintLiteral>),
|
||||
Raw(Context<ConstraintRaw>),
|
||||
Owner(Context<ConstraintOwner>),
|
||||
|
@ -359,7 +359,7 @@ pub struct ConstraintMut {}
|
|||
pub struct ConstraintSigner {}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ConstraintBelongsTo {
|
||||
pub struct ConstraintHasOne {
|
||||
pub join_target: Expr,
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::{
|
||||
ConstraintAddress, ConstraintAssociated, ConstraintAssociatedGroup, ConstraintAssociatedPayer,
|
||||
ConstraintAssociatedSpace, ConstraintAssociatedWith, ConstraintBelongsTo, ConstraintClose,
|
||||
ConstraintExecutable, ConstraintGroup, ConstraintInit, ConstraintLiteral, ConstraintMut,
|
||||
ConstraintAssociatedSpace, ConstraintAssociatedWith, ConstraintClose, ConstraintExecutable,
|
||||
ConstraintGroup, ConstraintHasOne, ConstraintInit, ConstraintLiteral, ConstraintMut,
|
||||
ConstraintOwner, ConstraintRaw, ConstraintRentExempt, ConstraintSeeds, ConstraintSeedsGroup,
|
||||
ConstraintSigner, ConstraintState, ConstraintToken, ConstraintTokenAuthority,
|
||||
ConstraintTokenMint, Context, PdaKind, Ty,
|
||||
|
@ -81,9 +81,16 @@ pub fn parse_token(stream: ParseStream) -> ParseResult<ConstraintToken> {
|
|||
.join(stream.span())
|
||||
.unwrap_or_else(|| ident.span());
|
||||
match kw.as_str() {
|
||||
"belongs_to" | "has_one" => ConstraintToken::BelongsTo(Context::new(
|
||||
// Deprecated since 0.11
|
||||
"belongs_to" => {
|
||||
return Err(ParseError::new(
|
||||
ident.span(),
|
||||
"belongs_to is deprecated, please use has_one",
|
||||
))
|
||||
}
|
||||
"has_one" => ConstraintToken::HasOne(Context::new(
|
||||
span,
|
||||
ConstraintBelongsTo {
|
||||
ConstraintHasOne {
|
||||
join_target: stream.parse()?,
|
||||
},
|
||||
)),
|
||||
|
@ -190,7 +197,7 @@ pub struct ConstraintGroupBuilder<'ty> {
|
|||
pub init: Option<Context<ConstraintInit>>,
|
||||
pub mutable: Option<Context<ConstraintMut>>,
|
||||
pub signer: Option<Context<ConstraintSigner>>,
|
||||
pub belongs_to: Vec<Context<ConstraintBelongsTo>>,
|
||||
pub has_one: Vec<Context<ConstraintHasOne>>,
|
||||
pub literal: Vec<Context<ConstraintLiteral>>,
|
||||
pub raw: Vec<Context<ConstraintRaw>>,
|
||||
pub owner: Option<Context<ConstraintOwner>>,
|
||||
|
@ -215,7 +222,7 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
|
|||
init: None,
|
||||
mutable: None,
|
||||
signer: None,
|
||||
belongs_to: Vec::new(),
|
||||
has_one: Vec::new(),
|
||||
literal: Vec::new(),
|
||||
raw: Vec::new(),
|
||||
owner: None,
|
||||
|
@ -275,7 +282,7 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
|
|||
init,
|
||||
mutable,
|
||||
signer,
|
||||
belongs_to,
|
||||
has_one,
|
||||
literal,
|
||||
raw,
|
||||
owner,
|
||||
|
@ -314,7 +321,7 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
|
|||
init: into_inner!(init),
|
||||
mutable: into_inner!(mutable),
|
||||
signer: into_inner!(signer),
|
||||
belongs_to: into_inner_vec!(belongs_to),
|
||||
has_one: into_inner_vec!(has_one),
|
||||
literal: into_inner_vec!(literal),
|
||||
raw: into_inner_vec!(raw),
|
||||
owner: into_inner!(owner),
|
||||
|
@ -371,7 +378,7 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
|
|||
ConstraintToken::Init(c) => self.add_init(c),
|
||||
ConstraintToken::Mut(c) => self.add_mut(c),
|
||||
ConstraintToken::Signer(c) => self.add_signer(c),
|
||||
ConstraintToken::BelongsTo(c) => self.add_belongs_to(c),
|
||||
ConstraintToken::HasOne(c) => self.add_has_one(c),
|
||||
ConstraintToken::Literal(c) => self.add_literal(c),
|
||||
ConstraintToken::Raw(c) => self.add_raw(c),
|
||||
ConstraintToken::Owner(c) => self.add_owner(c),
|
||||
|
@ -475,20 +482,17 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn add_belongs_to(&mut self, c: Context<ConstraintBelongsTo>) -> ParseResult<()> {
|
||||
fn add_has_one(&mut self, c: Context<ConstraintHasOne>) -> ParseResult<()> {
|
||||
if self
|
||||
.belongs_to
|
||||
.has_one
|
||||
.iter()
|
||||
.filter(|item| item.join_target == c.join_target)
|
||||
.count()
|
||||
> 0
|
||||
{
|
||||
return Err(ParseError::new(
|
||||
c.span(),
|
||||
"belongs_to target already provided",
|
||||
));
|
||||
return Err(ParseError::new(c.span(), "has_one target already provided"));
|
||||
}
|
||||
self.belongs_to.push(c);
|
||||
self.has_one.push(c);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ const LangErrorCode = {
|
|||
|
||||
// Constraints.
|
||||
ConstraintMut: 140,
|
||||
ConstraintBelongsTo: 141,
|
||||
ConstraintHasOne: 141,
|
||||
ConstraintSigner: 142,
|
||||
ConstraintRaw: 143,
|
||||
ConstraintOwner: 144,
|
||||
|
@ -119,7 +119,7 @@ const LangErrorMessage = new Map([
|
|||
|
||||
// Constraints.
|
||||
[LangErrorCode.ConstraintMut, "A mut constraint was violated"],
|
||||
[LangErrorCode.ConstraintBelongsTo, "A belongs_to constraint was violated"],
|
||||
[LangErrorCode.ConstraintHasOne, "A has_one constraint was violated"],
|
||||
[LangErrorCode.ConstraintSigner, "A signer constraint was violated"],
|
||||
[LangErrorCode.ConstraintRaw, "A raw constraint as violated"],
|
||||
[LangErrorCode.ConstraintOwner, "An owner constraint was violated"],
|
||||
|
|
Loading…
Reference in New Issue