Skip to content

Commit

Permalink
Improve extension data validation (#68)
Browse files Browse the repository at this point in the history
* Improve extension data validation

* Update autogenerated code

* Update tests

* Fix tests
  • Loading branch information
febo authored May 9, 2024
1 parent aac6356 commit e9654be
Show file tree
Hide file tree
Showing 14 changed files with 539 additions and 51 deletions.
13 changes: 13 additions & 0 deletions clients/js/asset/src/generated/errors/asset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,19 @@ export class AlreadyInGroupError extends ProgramError {
codeToErrorMap.set(0x14, AlreadyInGroupError);
nameToErrorMap.set('AlreadyInGroup', AlreadyInGroupError);

/** ExtensionLengthInvalid: Extension length invalid */
export class ExtensionLengthInvalidError extends ProgramError {
override readonly name: string = 'ExtensionLengthInvalid';

readonly code: number = 0x15; // 21

constructor(program: Program, cause?: Error) {
super('Extension length invalid', program, cause);
}
}
codeToErrorMap.set(0x15, ExtensionLengthInvalidError);
nameToErrorMap.set('ExtensionLengthInvalid', ExtensionLengthInvalidError);

/**
* Attempts to resolve a custom program error from the provided error code.
* @category Errors
Expand Down
10 changes: 8 additions & 2 deletions clients/js/asset/test/extensions/creators.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,13 +167,19 @@ test("it cannot create an asset with invalid creators' total share", async (t) =
.fill(0)
.map(() => ({ address: generateSigner(umi).publicKey, share: 10 }));

// And we try to initialize an asset with a creators extension.
const promise = initialize(umi, {
// And we initialize an asset with a creators extension.
await initialize(umi, {
asset,
payer: umi.identity,
extension: creators(addresses),
}).sendAndConfirm(umi);

const promise = create(umi, {
asset,
payer: umi.identity,
name: 'Asset with creators',
}).sendAndConfirm(umi);

// Then we expect an error.
await t.throwsAsync(promise, { message: /Extension data invalid/ });
});
Expand Down
4 changes: 2 additions & 2 deletions clients/js/bridge/test/royalties.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ test('pubkeymatch failing blocks a transfer on a group asset', async (t) => {
creators: [
{
address: umi.identity.publicKey,
verified: false,
verified: true,
share: 100,
},
],
Expand Down Expand Up @@ -243,7 +243,7 @@ test('pubkeymatch failing blocks a transfer on a group asset', async (t) => {
creators: [
{
address: umi.identity.publicKey,
verified: false,
verified: true,
share: 100,
},
],
Expand Down
3 changes: 3 additions & 0 deletions clients/rust/asset/src/generated/errors/asset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ pub enum AssetError {
/// 20 (0x14) - Asset is already in a group
#[error("Asset is already in a group")]
AlreadyInGroup,
/// 21 (0x15) - Extension length invalid
#[error("Extension length invalid")]
ExtensionLengthInvalid,
}

impl solana_program::program_error::PrintProgramError for AssetError {
Expand Down
101 changes: 101 additions & 0 deletions clients/rust/asset/tests/create.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#![cfg(feature = "test-sbf")]
pub mod utils;

use nifty_asset::{
errors::AssetError,
extensions::{Attributes, AttributesBuilder, ExtensionBuilder},
instructions::{AllocateBuilder, CreateBuilder},
state::{Asset, Discriminator, Standard, State},
Expand Down Expand Up @@ -151,4 +153,103 @@ mod create {
assert_eq!(attributes[0].name.as_str(), "hat");
assert_eq!(attributes[0].value.as_str(), "nifty");
}

#[tokio::test]
async fn create_with_invalid_extension_length_fails() {
let mut context = ProgramTest::new("asset_program", nifty_asset::ID, None)
.start_with_context()
.await;

// Given a new keypair.

let asset = Keypair::new();

// And an extension.

let mut attributes = AttributesBuilder::default();
attributes.add("hat", "nifty");
let data = attributes.data();

// When we try to create a new asset with an invalid extension length.

let ix = CreateBuilder::new()
.asset(asset.pubkey())
.authority(context.payer.pubkey(), false)
.owner(context.payer.pubkey())
.payer(Some(context.payer.pubkey()))
.system_program(Some(system_program::id()))
.name("name".to_string())
.extensions(vec![ExtensionInput {
extension_type: ExtensionType::Attributes,
length: 1,
data: Some(data),
}])
.instruction();

let tx = Transaction::new_signed_with_payer(
&[ix],
Some(&context.payer.pubkey()),
&[&context.payer, &asset],
context.last_blockhash,
);
let err = context
.banks_client
.process_transaction(tx)
.await
.unwrap_err();

// Then we expect an error.

assert_custom_error!(err, AssetError::ExtensionLengthInvalid);
}

#[tokio::test]
async fn create_with_missing_extension_data_fails() {
let mut context = ProgramTest::new("asset_program", nifty_asset::ID, None)
.start_with_context()
.await;

// Given a new keypair.

let asset = Keypair::new();

// And an extension.

let mut attributes = AttributesBuilder::default();
attributes.add("hat", "nifty");
let data = attributes.data();

// When we try to create a new asset with an invalid extension length.

let ix = CreateBuilder::new()
.asset(asset.pubkey())
.authority(context.payer.pubkey(), false)
.owner(context.payer.pubkey())
.payer(Some(context.payer.pubkey()))
.system_program(Some(system_program::id()))
.name("name".to_string())
.extensions(vec![ExtensionInput {
extension_type: ExtensionType::Attributes,
// increase the data length
length: data.len() as u32 + 100,
data: Some(data),
}])
.instruction();

let tx = Transaction::new_signed_with_payer(
&[ix],
Some(&context.payer.pubkey()),
&[&context.payer, &asset],
context.last_blockhash,
);
let err = context
.banks_client
.process_transaction(tx)
.await
.unwrap_err();

// Then we expect an error.

assert_custom_error!(err, AssetError::ExtensionDataInvalid);
}
}
4 changes: 2 additions & 2 deletions clients/rust/asset/tests/handover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ use nifty_asset::{
ZeroCopy,
};
use nifty_asset_types::state::Standard;
use solana_program_test::{tokio, BanksClientError, ProgramTest};
use solana_program_test::{tokio, ProgramTest};
use solana_sdk::{
instruction::InstructionError,
signature::{Keypair, Signer},
system_program,
transaction::{Transaction, TransactionError},
transaction::Transaction,
};

mod handover {
Expand Down
Loading

0 comments on commit e9654be

Please sign in to comment.