failed to send transaction: Cross-program invocation with unauthorized signer or writable account - anchor

I am trying to build a web3 based e-commerce site using Anchor.
I've just started learning about PDAs and there's a error I've been getting for hours, like the one in the title.
My contract:
#[program]
pub mod dailsap_store_contract {
use super::*;
pub fn create_collection(
ctx: Context<CreateCollection>,
name: String,
description: String,
image_uri: String,
) -> Result<()> {
let collection: &mut Account<Collection> = &mut ctx.accounts.collection;
let authority: &Signer = &ctx.accounts.authority;
let clock: Clock = Clock::get().unwrap();
let bump = *ctx.bumps.get("collection").unwrap();
if name.chars().count() > 50 {
return Err(ErrorCode::CollectionNameTooLong.into());
}
if description.chars().count() > 250 {
return Err(ErrorCode::CollectionDescriptionTooLong.into());
}
if image_uri.chars().count() > 60 {
return Err(ErrorCode::CollectionImageUrlTooLong.into());
}
collection.authority = *authority.key;
collection.timestamp = clock.unix_timestamp;
collection.name = name;
collection.description = description;
collection.image = image_uri;
collection.bump = bump;
Ok(())
}
pub fn update_collection(
ctx: Context<UpdateCollection>,
name: String,
description: String,
image_uri: String,
) -> Result<()> {
let base_collection: &mut Account<Collection> = &mut ctx.accounts.collection_account;
base_collection.name = name;
base_collection.description = description;
base_collection.image = image_uri;
Ok(())
}
}
#[derive(Accounts)]
pub struct CreateCollection<'info> {
#[account(mut)]
pub authority: Signer<'info>,
#[account(init, payer=authority, space = Collection::LEN, seeds=[b"collection", collection.key().as_ref()], bump)]
pub collection: Account<'info, Collection>,
#[account(address = system_program::ID)]
pub system_program: Program<'info, System>,
}
#[account]
pub struct Collection {
authority: Pubkey,
timestamp: i64,
name: String,
description: String,
image: String,
bump: u8,
}
Frontend:
const collection = anchor.web3.Keypair.generate();
const [collectionPDA, _] = await anchor.web3.PublicKey.findProgramAddress(
[
anchor.utils.bytes.utf8.encode("collection"),
collection.publicKey.toBuffer(),
],
program.programId
);
await program.methods
.createCollection(
"This is collection name",
"This is collection description",
"Hello World"
)
.accounts({
collection: collectionPDA,
authority: anchor.AnchorProvider.env().publicKey,
systemProgram: anchor.web3.SystemProgram.programId,
})
.rpc();
The problem should be here: seeds=[b"collection", collection.key().as_ref()]
The source from which I received help: https://book.anchor-lang.com/anchor_in_depth/PDAs.html
But I'm getting errors in a way I don't understand
can you help?

To be honest, I'm surprised the program got so far! The program-derived address is meant to be derived from a set of seeds and the program id, and in your case, the collection address is using itself as a seed, which would normally mean infinite recursion. But in this case, it only goes down one level and fails to derive itself.
Try any other seeds on your collection address, even something like:
#[account(init, payer=authority, space = Collection::LEN, seeds=[b"collection", authority.key().as_ref()], bump)]
pub collection: Account<'info, Collection>,

I came up with a solution like this, I'm not sure how logical it is.
...
#[program]
pub mod dailsap_store_contract {
use super::*;
pub fn create_collection(
ctx: Context<CreateCollection>,
id: Pubkey,
name: String,
description: String,
image_uri: String,
) -> Result<()> {
let collection: &mut Account<Collection> = &mut ctx.accounts.collection;
let authority: &Signer = &ctx.accounts.authority;
let clock: Clock = Clock::get().unwrap();
let bump = *ctx.bumps.get("collection").unwrap();
if name.chars().count() > 50 {
return Err(ErrorCode::CollectionNameTooLong.into());
}
...
#[derive(Accounts)]
#[instruction(id: Pubkey)]
pub struct CreateCollection<'info> {
#[account(mut)]
pub authority: Signer<'info>,
#[account(init, payer=authority, space = Collection::LEN, seeds=[b"collection", id.as_ref()], bump)]
pub collection: Account<'info, Collection>,
#[account(address = system_program::ID)]
pub system_program: Program<'info, System>,
}
#[account]
pub struct Collection {
id: Pubkey,
authority: Pubkey,
timestamp: i64,
name: String,
description: String,
image: String,
bump: u8,
}
...
Frontend:
const collection = anchor.web3.Keypair.generate();
const [collectionPDA, _] = await anchor.web3.PublicKey.findProgramAddress(
[
Buffer.from(anchor.utils.bytes.utf8.encode("collection")),
collection.publicKey.toBuffer(),
],
program.programId
);
await program.methods
.createCollection(
collection.publicKey,
"This is collection name",
"This is collection description",
"Hello World"
)
.accounts({
collection: collectionPDA,
authority: anchor.AnchorProvider.env().publicKey,
systemProgram: anchor.web3.SystemProgram.programId,
})
.rpc();

Related

Toggle a boolean within a struct in zig, possible?

To toggle* a boolean I normally use boolean = !boolean like this:
var boolean: bool = true;
boolean = !boolean;
std.debug.print("My bool is: {}\n", .{boolean}); //My bool is: false
But how do I achieve this for booleans within a struct? Or is it not possible?
const std = #import("std");
pub fn main() void {
//Struct with default values:
const animal = struct {
tail: bool = true,
wings: bool = false,
horns: bool = false,
paws: bool = true,
};
//Struct instances:
var has = animal{};
//This works alright:
//var hasno = animal{.tail = false, .wings = true, .horns = true, .paws = false};
//FAILS: error: expected type 'bool', found '#TypeOf(.enum_literal)'
var hasno = animal{ .tail = !.tail }; //, .wings = !.wings, .horns = !.horns, .paws = !.paws };
//Debug printing:
std.debug.print("Animal has tail: {}, wings: {}, horns: {}, paws: {}\n", .{ has.tail, has.wings, has.horns, has.paws });
std.debug.print("Animal has no tail: {}, wings: {}, horns: {}, paws: {}\n", .{ hasno.tail, hasno.wings, hasno.horns, hasno.paws });
}
Test code for yourself online in zig playground:
https://zig-play.dev
*give it the opposite value of what it was, without knowing what it was.
Like if (boolean == true) boolean = false; else boolean = true; But I'm wondering if it is possible with the (bang) operator for booleans within struct.
const std = #import("std");
const Animal = struct {
tail: bool,
};
pub fn main() void {
var animal = Animal { .tail = true };
std.debug.print("{}\n", .{ animal });
animal.tail = !animal.tail;
std.debug.print("{}\n", .{ animal });
}
Prints:
main.Animal{ .tail = true }
main.Animal{ .tail = false }

Classifier 'Context' does not have a companion object, and thus must be initialized here

Here is my code
fun Uri.getOriginalFileName(context: Context): String? {
return context.contentResolver.query(this, null, null, null, null)?.use {
val nameColumnIndex = it.getColumnIndex(OpenableColumns.DISPLAY_NAME)
it.moveToFirst()
it.getString(nameColumnIndex)
}
}
#Composable
fun AppNotice() {
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "*/*"; ///
intent.addCategory(Intent.CATEGORY_OPENABLE);
val launcher = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) {
activityResult -> if (activityResult.resultCode == RESULT_OK)
{
Log.d("appDebug", "oky")
var uri = intent.getData()
val name: String? = uri?.getOriginalFileName(Context)
Log.d("seeFile", "$name")
}
else {
Log.d("appDebug", "Denied")
}
Button(onClick={launcher.launch(intent)})
{Text("Button")}
}
Context is a class then how to know what method will i need in this line/context name: String? = uri?.getOriginalFileName(Context)
I went to adroid.dev page but found a huge page and cant figure out what i need since saw only few uri permission related stuffs.

Have short error message using nom with nom_locate

I am trying to parse using nom with nom_locate, following this tutorial. I only want output in the format:
Error: line 5, column 1
But currently I get:
Error: Parsing Failure: ParseError { span: LocatedSpan { offset: 37, line: 5, fragment: "{{G]\nK(1)key [J]\n", extra: () }, message: "Error: line 5, column 1" }
Relevant code:
pub type Span<'a> = LocatedSpan<&'a str>;
pub type IResult<'a, O> = nom::IResult<Span<'a>, O, ParseError<'a>>;
#[derive(Debug, PartialEq)]
pub struct ParseError<'a> {
span: Span<'a>,
message: String,
}
impl<'a> ParseError<'a> {
pub fn new(message: String, span: Span<'a>) -> Self {
Self {
span,
message,
}
}
}
impl<'a> nom::error::ParseError<Span<'a>> for ParseError<'a> {
fn from_error_kind(input: Span<'a>, _: nom::error::ErrorKind) -> Self {
Self::new(format!("Error: line {}, column {}", input.location_line(), input.location_line()), input)
}
fn append(input: Span<'a>, _: nom::error::ErrorKind, _: Self) -> Self {
Self::new(format!("Error: line {}, column {}", input.location_line(), input.location_line()), input)
}
fn from_char(input: Span<'a>, _: char) -> Self {
Self::new(format!("Error: line {}, column {}", input.location_line(), input.location_line()), input)
}
}
pub fn job(s: Span) -> IResult<Vec<entities::Step>> {
let (s, steps) = many1(job_lines)(s)?;
Ok((s, steps))
}
fn job_lines(s: Span) -> IResult<entities::Step> {
let (s, name) = match step_name(s) {
Ok((s, name)) => (s, name),
Err(nom::Err::Error(_)) => {
let line = s.location_line();
let column = s.get_column();
return Err(nom::Err::Failure(ParseError::new(
format!("Error: line {}, column {}", line, column),
s,
)));
},
Err(e) => return Err(e),
};
Ok((s, name))
}
Relevant error code in main:
let steps = match input::parsers::job(input::parsers::Span::new(&input)) {
Ok((_, steps)) => steps,
Err(error) => {
eprintln!("{}", error);
std::process::exit(1)
}
};
What do I need to do to get the short error message instead of the extensive one?
EDIT:
I deleted the span property from the custom ParseError and then the Error output becomes:
Parsing Failure: ParseError { message: "Error: line 5, column 1" }
Much better, but question remains: can I get of everything except of the message itself?
As you surmised, error is a nom::Err::Err which is an enum, so you will need to match on that to get at the inner error:
let steps = match input::parsers::job(input::parsers::Span::new(&input)) {
Ok((_, steps)) => steps,
Err(nom::Err::Failure (error)) => {
eprintln!("{}", error.message);
std::process::exit(1)
},
Err(error) => {
eprintln!("Unknown error: {}", error);
std::process::exit(1)
},
};

Transforming attributes into identifiers on proc macro derive

I'm writing my first proc macro and despite trying to read through the source for thiserror, structopt and derive_more I can't seem to find exactly what I'm looking for. I want to transform this:
#[derive(Attach)]
#[attach(foo(SomeType, OtherType))]
#[attach(bar(OtherType))]
struct Plugin {}
into this:
impl Attach for Plugin {
fn attach(self, srv: &mut Server) {
let this = Arc::new(self);
srv.foo_order(this.clone(), &[TypeId::of::<SomeType>(), TypeId::of::<OtherType>()]);
srv.bar_order(this, &[TypeId::of::<OtherType>()]);
}
}
I've started writing a proc macro but got bungled up trying to parse the attributes:
extern crate proc_macro;
use proc_macro::{Span, TokenStream};
use quote::quote;
use std::any::TypeId;
use syn::{
parse::ParseStream, parse_macro_input, Attribute, AttributeArgs, DeriveInput, Ident, Result,
};
#[proc_macro_derive(Attach, attributes(attach))]
pub fn register_macro(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
impl_register(input)
}
fn impl_register(input: DeriveInput) -> TokenStream {
let name = &input.ident;
let attrs = &input.attrs;
for attr in attrs {
if attr.path.is_ident("attach") {
parse_attach_attribute(&attr);
}
}
println!("{:#?}", input);
TokenStream::from(quote! {
impl ::corten::Attach for #name {
fn attach(self, srv: &mut ::corten::Server) {
}
}
})
}
fn parse_attach_attribute(attr: &Attribute) -> Result<Dependency> {
let list: syn::MetaList = attr.parse_args()?;
// println!("{:#?}", list);
let ident = list.path.get_ident().expect("expected identifier");
let method = Ident::new(&format!("{}_order", ident), ident.span());
println!("{:#?}", method);
let dependencies = list
.nested
.into_pairs()
.map(|pair| pair.into_value())
.collect::<Vec<_>>();
// How does one get the identifiers out of a NestedMeta?
println!("{:#?}", dependencies);
// attr.parse_args_with(|input: ParseStream| {
// let ident = input.p
// let method = Ident::new(&format!("{}_order", ident), Span::call_site());
// let dep = Dependency {
// method,
// }
// })
unimplemented!()
}
struct Dependency {
method: Ident,
dependencies: Vec<Ident>,
}
the difficulty I'm having is how to actually get the attributes list into a usable form? As far as I can tell, I need to get the "foo" and "bar" parsed from &[Attribute] so I can construct the method identifier, and also the "SomeType" & "OtherType" identifiers, which I'll all eventually feed into quote!. If I print the TokenStream in the console, all of the information is there:
[
Attribute {
pound_token: Pound,
style: Outer,
bracket_token: Bracket,
path: Path {
leading_colon: None,
segments: [
PathSegment {
ident: Ident {
ident: "attach",
span: #0 bytes(103..109),
},
arguments: None,
},
],
},
tokens: TokenStream [
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "predecode",
span: #0 bytes(110..119),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "SomeType",
span: #0 bytes(120..128),
},
Punct {
ch: ',',
spacing: Alone,
span: #0 bytes(128..129),
},
Ident {
ident: "OtherType",
span: #0 bytes(130..139),
},
],
span: #0 bytes(119..140),
},
],
span: #0 bytes(109..141),
},
],
},
Attribute {
pound_token: Pound,
style: Outer,
bracket_token: Bracket,
path: Path {
leading_colon: None,
segments: [
PathSegment {
ident: Ident {
ident: "attach",
span: #0 bytes(145..151),
},
arguments: None,
},
],
},
tokens: TokenStream [
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "preresolve",
span: #0 bytes(152..162),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "OtherType",
span: #0 bytes(163..172),
},
],
span: #0 bytes(162..173),
},
],
span: #0 bytes(151..174),
},
],
},
]
But I don't have a way to actually get at it. How do I get to tokens[0].stream.ident?
After much messing around I think I have something that works, although I'm happy to accept other answers that are better as I feel this is a bit messy:
extern crate proc_macro;
use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::{parse_macro_input, Attribute, DeriveInput, Ident, Result};
#[proc_macro_derive(Attach, attributes(attach))]
pub fn register_macro(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = parse_macro_input!(input as DeriveInput);
proc_macro::TokenStream::from(impl_register(input))
}
fn impl_register(input: DeriveInput) -> TokenStream {
let name = &input.ident;
let attrs = &input.attrs;
// println!("{:#?}", input);
let attrs = attrs
.iter()
.filter(|attr| attr.path.is_ident("attach"))
.map(|attr| parse_attach_attribute(&attr).expect("parse failed"))
.map(|dep| {
let method: Ident = dep.method;
let dependencies = dep.dependencies.iter().map(|ident: &Ident| {
quote! {
std::any::TypeId::of::<#ident>()
}
});
quote! {
srv.#method::<#name, _>(Arc::clone(&this), &[ #(#dependencies),* ]);
}
});
quote! {
impl corten::Attach for #name {
fn attach(self, srv: &mut corten::Server) {
let this = std::sync::Arc::new(self);
#(#attrs)*
}
}
}
}
fn parse_attach_attribute(attr: &Attribute) -> Result<Dependency> {
let list: syn::MetaList = attr.parse_args()?;
// println!("{:#?}", list);
let ident = list.path.get_ident().expect("expected identifier");
let method = Ident::new(&format!("{}_order", ident), Span::call_site());
println!("{:#?}", method);
let dependencies = list
.nested
.into_pairs()
.map(|pair| pair.into_value())
.filter_map(|pair| match pair {
syn::NestedMeta::Meta(meta) => match meta {
syn::Meta::Path(path) => path.get_ident().cloned(),
_ => panic!("only path meta supported"),
},
_ => panic!("lit not supported"),
})
.collect();
println!("{:#?}", dependencies);
Ok(Dependency {
method,
dependencies,
})
}
struct Dependency {
method: Ident,
dependencies: Vec<Ident>,
}

Neo4j/GraphQL augmented Schema

I'm trying to learn a bit about Neo4j's GraphQL integration. I'm using the GrandStack starter which can be found here. Grand Stack Starter. The starter doesn't use a lot of the boilerplate that you see in other GrapQL applications because, as I understand it, the Neo4j integration is supposed to bypass the need to double declare Schema and Resolvers. It uses Apollo Server and an "augmentedSchema" instead. Using the starter code I've tried to add some mutations to the schema, in this case, a deleteUser mutation. I keep getting an error, saying that the Mutation id defined more than once, when I know I'm only putting it in the code in one place. This is my schema.js:
import { neo4jgraphql } from "neo4j-graphql-js";
export const typeDefs = `
type User {
id: ID!
name: String
friends(first: Int = 10, offset: Int = 0): [User] #relation(name: "FRIENDS", direction: "BOTH")
reviews(first: Int = 10, offset: Int = 0): [Review] #relation(name: "WROTE", direction: "OUT")
avgStars: Float #cypher(statement: "MATCH (this)-[:WROTE]->(r:Review) RETURN toFloat(avg(r.stars))")
numReviews: Int #cypher(statement: "MATCH (this)-[:WROTE]->(r:Review) RETURN COUNT(r)")
}
type Business {
id: ID!
name: String
address: String
city: String
state: String
reviews(first: Int = 10, offset: Int = 0): [Review] #relation(name: "REVIEWS", direction: "IN")
categories(first: Int = 10, offset: Int =0): [Category] #relation(name: "IN_CATEGORY", direction: "OUT")
}
type Review {
id: ID!
stars: Int
text: String
business: Business #relation(name: "REVIEWS", direction: "OUT")
user: User #relation(name: "WROTE", direction: "IN")
}
type Category {
name: ID!
businesses(first: Int = 10, offset: Int = 0): [Business] #relation(name: "IN_CATEGORY", direction: "IN")
}
type Query {
users(id: ID, name: String, first: Int = 10, offset: Int = 0): [User]
businesses(id: ID, name: String, first: Int = 10, offset: Int = 0): [Business]
reviews(id: ID, stars: Int, first: Int = 10, offset: Int = 0): [Review]
category(name: ID!): Category
usersBySubstring(substring: String, first: Int = 10, offset: Int = 0): [User] #cypher(statement: "MATCH (u:User) WHERE u.name CONTAINS $substring RETURN u")
}
type Mutation {
deleteUser(id: ID!): User
}
`;
export const resolvers = {
Query: {
users: neo4jgraphql,
businesses: neo4jgraphql,
reviews: neo4jgraphql,
category: neo4jgraphql,
usersBySubstring: neo4jgraphql
},
Mutation: {
deleteUser: neo4jgraphql
}
};
Here's my index:
import { typeDefs, resolvers } from "./graphql-schema";
import { ApolloServer, gql, makeExecutableSchema } from "apollo-server";
import { v1 as neo4j } from "neo4j-driver";
import { augmentSchema } from "neo4j-graphql-js";
import dotenv from "dotenv";
dotenv.config();
const schema = makeExecutableSchema({
typeDefs,
resolvers
});
// augmentSchema will add autogenerated mutations based on types in schema
const augmentedSchema = augmentSchema(schema);
const driver = neo4j.driver(
process.env.NEO4J_URI || "bolt://localhost:7687",
neo4j.auth.basic(
process.env.NEO4J_USER || "neo4j",
process.env.NEO4J_PASSWORD || "neo4j"
)
);
if (driver){
console.log("Database Connected")
} else{
console.log("Database Connection Error")
}
const server = new ApolloServer({
// using augmentedSchema (executable GraphQLSchemaObject) instead of typeDefs and resolvers
//typeDefs,
//resolvers,
context: { driver },
// remove schema and uncomment typeDefs and resolvers above to use original (unaugmented) schema
schema: augmentedSchema
});
server.listen(process.env.GRAPHQL_LISTEN_PORT, '0.0.0.0').then(({ url }) => {
console.log(`GraphQL API ready at ${url}`);
});
Error Message:
No other code from the starter has been changed. I haven't been able to find much info on the augmentedSchema in the docs. If anyone can point me in the right direction I would appreciate it.
The issue was caused by the augmentedSchema, which automatically creates default mutations for each type i.e. in this case it had already created delete user, update user, and add user. You can see this when you run the GraphiQL server. So I was double declaring the delete user mutation.

Resources