Giter Club home page Giter Club logo

anchor's People

Contributors

acheroncrypto avatar armaniferrante avatar arrowana avatar aursen avatar callensm avatar canardmandarin avatar cavemanloverboy avatar chewingglass avatar cqfd avatar cryptopapi997 avatar dependabot[bot] avatar fanatid avatar henry-e avatar italoacasas avatar johndoe389 avatar johnrees avatar kklas avatar macalinao avatar metaproph3t avatar michaelhly avatar mikemaccana avatar norbertbodziony avatar ochaloup avatar paul-schaaf avatar skrrb avatar stegabob avatar suscd avatar thesoftwarejedi avatar tomlinton avatar u32luke avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

anchor's Issues

ts: Client transaction builder pattern

Constructing transactions is a bit bulky right now due to having to specify multiple accounts and instructions all in one function call. We should consider offering a builder api, similar to what the rust client does.

Switch to stable rust

Requires the solana bpf sdk to be on Rust 1.45 or above, so that we can remove #![feature(proc_macro_hygiene)] everywhere.

Until we do this, CI will sometimes fail, because rustfmt is not always available on the latest nightly, so travis should also probably pin the nightly version.

Deserialize Vec of Accounts

Consider implementing the Accounts trait for Vec, where all accounts in the &[AccountInfo] slice are consumed and deserialized into the vec.

Add trait implementations to IDL

Currently, any implementation of a program #[interface] trait can only be used via CPI. We should add these handlers to the IDL so that clients can call them directly, potentially. In the mean time, if one wants to invoke these methods from clients, they can should expose methods outside the trait, and have the trait invoke these methods.

Auto validation for common types

We should automatically generate validation code for common types, e.g. all sysvars.

For example,

#[derive(Accounts)]
pub struct MyStruct {
  pub clock: Clock, 
  pub rent: Rent,
}

Should work without specifying additional attributes.

Error codes for Accounts constraints

The DSL is currently very lazy with error codes. We should do this properly, generating an error for each constraint, adding those to the IDL, and having all clients report typed, informative errors, when the runtime responds with a particular error code.

There's also some boilierplate we should eliminate with a macro when creating custom errors for programs.

Global state structs + instructions

Provide the ability to generate a global state struct and methods on it. This is useful when you want Solana programs to behave as if they have state (even though they do not). Because account sizes are finite, this can't be the dominate programming pattern. But it can be complementary to what we have now (i.e. defining instructions and accounts separately).

#[program]
mod registry {

    #[state]
    pub struct Foo {
        data: Pubkey,
    }

    impl Foo {
        pub fn new(data: Pubkey) -> Result<Self, Error> {
            Ok(Registry {
               data,
            })
        } 

        pub fn some_instruction(&mut self, data: Pubkey) -> Result<(), Error> {
          self.data = data;
          Ok(())
        }
    }
}

Account discriminators and `#[account(init)]`

Proposal

Similar to what the dex does with AccountFlags, we should transparently add a discriminator field, which uniquely identifies the account type, in the first 8 bytes of every program-owned account.

If the account discriminator doesn't match when the Accounts struct being deserialized, then the instruction should error out.

We achieve this with a new attribute #[account], which implements four traits:

  1. BorshSerialize
  2. BorshDeserialize
  3. AccountSerialize
  4. AccountDeserialize

Where the implementations of AccountSerialize and AccountDeserialize do the discriminator check on the first 8 bytes and Borsh ser/deser of the rest of the account data.

Concretely, this looks like.

#[account] 
pub struct Bar {
   ...
}

When checking the account discriminator, the one exception would be if the account is marked with a newly proposed attribute, #[account(init)], in which case, the discriminator should be zero, because an account is being initialized for the first time (and the discriminator will be set on the instruction execution).

#[derive(Accounts)]
pub struct MyInstruction<'info> {
  #[account(init)]
  pub foo: ProgramAccount<'info, Bar>,
}

Two Discriminator Options

Using a 1-indexed discriminator means all accounts need to be defined inside the #[program] decorated mod, so that the macro knows what index to assign a given Account. Alternatively, instead of incrementing a 1-indexed discriminator, we could just hash (SHA256) the name of the account and take the first 8 bytes to create the discriminator, in which case, the Accounts can be defined outside (or inside) of the #[program] mod.

Both for aesthetic, flexibility, and immediate implementation reasons, I prefer hashing the account name. Note that we can define the hashed discriminator at compile time (in the macro), so there is no runtime cost vs a 1-indexed counter. Aesthetically, it means only instruction handlers need to be inside the #[program] module. In terms of implementation, it allows all account related serialization to be defined completely within the derive macro. Otherwise, the #[program] macro needs to handle this logic.

(A third option would be to have the programmer manually specify the discriminator. The developer could do this by just manually implementing the AccountSerialize and AccountDeserialize traits instead of using the #[account] macro.)

spl: Rename TokenAccount

CpiAccount<'info, TokenAccount> has one too many Accounts for me. Lets rename TokenAccount -> Token. I'm not a fan of calling it Account as the spl program does, since it overloads the word, which is confusing--though Token is potentially confusing as well (when coming from Ethereum's programming model).

Switch to sighash

Currently methods are dispatched based upon a generated rust enum, where each variant corresponds to one of the instruction handlers. The problem with this is that a method in one program will have a different "discriminator" tag than the same method in another program if the order of the function defined in the file is different. This makes defining interfaces inconvenient. One solution to this is to switch to something like Ethereum's sighash instead of using an enum.

Pull Sysvars out of Accounts structs

Sometimes sysvars are irrelevant to the application logic. For example, when initializing a program owned account, a rent exemption check is done, requiring the Rent sysvar to be included into the accounts set as follows.

#[derive(Accounts)]
pub struct MyAccounts {
  #[account(init)]
  my_account: ProgramAccount<'info, Foo>,
  rent: Sysvar<'info, Rent>,
}

It would be nice for the application to omit the sysvar here

#[derive(Accounts)]
pub struct MyAccounts {
  #[account(init)]
  my_account: ProgramAccount<'info, Foo>,,
}

And have it automatically added to another field of the program's Context object, when needed. In doing this, we would be setting the convention to not have sysvars in the accounts struct, so we would have to have a separate way of explicitly adding them (again, to a separate field on the Context object) when needed. One solution, would be to add a new inert attribute to mark the sysvars needed. For example,

#[derive(Accounts)]
#[sysvar(clock, rent)]
pub struct MyAccounts {
  #[account(init)]
  my_account: ProgramAccount<'info, Foo>,,
}

Store IDLs at determistic account address

We can do what we do for the program state struct, i.e., store the IDL JSON at a determistic account address as a function of nothing but the program_id.

This will allow clients to easily interact with any program written in Anchor using nothing but the program_id.

Tasks:

  • CLI stores the IDL on deploy
  • TypeScript client API anchor.Program.at(<PROGRAM-ID>) which generates a client from the program address

Add upgrade program command

Unlike the solana program deploy command, the anchor deploy command deploys to a new address everytime. To upgrade, we should implement an explicit anchor upgrade command.

Manually create typed CPI clients for SPL programs

For SPL programs, namely the token program, we should create clients for CPI that can be created from the accounts array. I.e. a manual version of #7, since of course the SPL programs aren't written in this framework.

Parse IDL from entire crate

Currently the IDL is created by parsing the src/lib.rs file. Instead, we should walk the entire crate to allow for larger programs to be more organized.

For example, it would be nice to only have nothing but the #[program] mod in src/lib.rs and all the separate handlers be in separate files alongside the associated instruction's Accounts struct. Similarly, an accounts module.

docs: Show entire state struct example

Currently we cut off the bottom of the file to emphasize the part of the docs that actually matters. However, this can be confusing when people copy and paste the code locally, since it won't compile.

ts: getProgramAccounts for each account type

We should provide a getProgramAccounts method that filters on the account discriminator, which has the effect of getting all accounts of a given type associated with a program.

CPI client for state structs

Generate CPI methods for the state struct instructions, similar to what we do for non-state-struct instructions.

Add `init` field to account IDL

Filing a tracking issue, though I don't love the idea at the moment and am inclined to throw this idea away.

IDL change and client generation

An additional feature the #[account(init)] attribute enables is the ability for clients to know when they should create accounts in the same transaction as executing a program instruction.

Currently, when executing this type of instruction, clients must manually add the account creation instruction as follows.

// The Account to create.
const myAccount = new anchor.web3.Account();

// Atomically create the new account and initialize it with the program.
await program.rpc.myInstruction(...args, {
  accounts: {
    myAccount: myAccount.publicKey,
  },
  signers: [myAccount],
  instructions: [
    await program.account.MyAccount.createInstruction(myAccount),
  ],
});

With the #[anchor(init)] attribute, this example can be transformed into

await program.rpc.myInstruction(...args);

Since the client generator can read a new isInit field in the IDL

// idl.json
{
...,
instructions: {
  ...,
  {
    "name:" "myInstruction",
    "accounts": [...],
    "isInit": true,
    "isMut": true,
    "isSigner": true,
     ...
   }
}

CPI Client Generation

We should generate clients for performing CPI. So that programs can import a crate, auto-deserialize a client from all the accounts, and make a high level calls to other programs without manually dealing with all the AccountInfo structs and instruction serialization.

Add example with manual deserialization.

We should add an example with complexity analogous to the lockup example, where we don't use borsh and manually serialize/deserialize everything by implementing the various Anchor traits--and fix any issues that pop up in the process.

Provide separate Account and AccountBox types

Currently we use ProgramAccount to refer to accounts owned by the current program. This type boxes it's inner account by default (needed to sometimes get around BPF stack size limits). Instead, we should provide a non-boxed version with type AccountBox = Box<NonBoxedVersion>; as the boxed variant.

Accounts + Program IDL/Schema traits

Motivation

Suppose I had a field foo of type crate_a::MyAccountsA that is embedded into crate_b::MyAccountsB as follows.

// crate_a/src/lib.rs

#[derive(Accounts)]
pub struct MyAccountsA {
 ...
}
// crate_b/src/lib.rs

#[derive(Accounts)]
pub struct MyAccountsB {
  foo: crate_a::MyAccountsA,
}

I would want the IDL emitted for crate_b to have all the type i+ account nformation for foo.

Currently this information is only available to crate_a, and so crate_b would either have to re-define crate_a::MyAccountsA in its own src/lib.rs or use all the accounts in flattened form, instead of composing crate_a::MyAccountsA directly.

Solution

To achieve this, we can have the various macros generate trait implementations providing IDL/type information. Additionally, we probably need to add some type of build.rs file that calls these generated traits to output the IDL, instead of just parsing the program's file directly, as we do now.

The build steps might be organized into

  1. Walk entire crate to find IDL types.
  2. Generate idl.rs file, invoking the traits on the IDL types.
  3. Emit IDL by running the build.rs file

Constraints on account collections

For example

#[derive(Accounts)]
pub struct MyStruct<'info> {
    #[account(signer)]
    pub authority: Vec<AccountInfo<'info>>,
}

Would check that all accounts in the vec are signers.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.