Skip to content

Commit

Permalink
Add tests and more error handling to Oracle borrowing and slicing
Browse files Browse the repository at this point in the history
  • Loading branch information
danenbm committed May 8, 2024
1 parent c17a462 commit 80178c4
Show file tree
Hide file tree
Showing 2 changed files with 156 additions and 3 deletions.
137 changes: 137 additions & 0 deletions clients/js/test/externalPlugins/oracle.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2388,3 +2388,140 @@ test('it can update oracle to different size external plugin', async (t) => {
],
});
});

test('create does not panic when oracle account does not exist', async (t) => {
const umi = await createUmi();
const oracleSigner = generateSigner(umi);

const asset = generateSigner(umi);
const result = create(umi, {
asset,
name: 'Test name',
uri: 'https://example.com',
plugins: [
{
type: 'Oracle',
resultsOffset: {
type: 'Anchor',
},
lifecycleChecks: {
create: [CheckResult.CAN_REJECT],
update: [CheckResult.CAN_REJECT],
transfer: [CheckResult.CAN_REJECT],
burn: [CheckResult.CAN_REJECT],
},
baseAddress: oracleSigner.publicKey,
},
],
}).sendAndConfirm(umi);

await t.throwsAsync(result, { name: 'InvalidOracleAccountData' });
});

test('transferring an asset does not panic when oracle account does not exist', async (t) => {
const umi = await createUmi();
const oracleSigner = generateSigner(umi);

const asset = await createAsset(umi, {
plugins: [
{
type: 'Oracle',
resultsOffset: {
type: 'Anchor',
},
lifecycleChecks: {
transfer: [CheckResult.CAN_REJECT],
},
baseAddress: oracleSigner.publicKey,
},
],
});

await assertAsset(t, umi, {
...DEFAULT_ASSET,
asset: asset.publicKey,
owner: umi.identity.publicKey,
oracles: [
{
type: 'Oracle',
resultsOffset: {
type: 'Anchor',
},
authority: {
type: 'UpdateAuthority',
},
baseAddress: oracleSigner.publicKey,
lifecycleChecks: {
transfer: [CheckResult.CAN_REJECT],
},
pda: undefined,
},
],
});

const newOwner = generateSigner(umi);
const result = transfer(umi, {
asset,
newOwner: newOwner.publicKey,
}).sendAndConfirm(umi);

await t.throwsAsync(result, { name: 'InvalidOracleAccountData' });
});

test.skip('transferring an asset does not panic when oracle account is too small', async (t) => {
const umi = await createUmi();
const newAccount = generateSigner(umi);

// Create an invalid oracle account that is an account with 3 bytes.
await createAccount(umi, {
newAccount,
lamports: sol(0.1),
space: 3,
programId: umi.programs.get('mplCore').publicKey,
}).sendAndConfirm(umi);

const asset = await createAsset(umi, {
plugins: [
{
type: 'Oracle',
resultsOffset: {
type: 'NoOffset',
},
lifecycleChecks: {
transfer: [CheckResult.CAN_REJECT],
},
baseAddress: newAccount.publicKey,
},
],
});

await assertAsset(t, umi, {
...DEFAULT_ASSET,
asset: asset.publicKey,
owner: umi.identity.publicKey,
oracles: [
{
type: 'Oracle',
resultsOffset: {
type: 'NoOffset',
},
authority: {
type: 'UpdateAuthority',
},
baseAddress: newAccount.publicKey,
lifecycleChecks: {
transfer: [CheckResult.CAN_REJECT],
},
pda: undefined,
},
],
});

const newOwner = generateSigner(umi);
const result = transfer(umi, {
asset,
newOwner: newOwner.publicKey,
}).sendAndConfirm(umi);

await t.throwsAsync(result, { name: 'InvalidOracleAccountData' });
});
22 changes: 19 additions & 3 deletions programs/mpl-core/src/plugins/oracle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,18 @@ impl Oracle {
.ok_or(MplCoreError::MissingExternalAccount)?;

let offset = self.results_offset.to_offset_usize();
let validation_result =
OracleValidation::deserialize(&mut &(*oracle_account.data).borrow()[offset..])
.map_err(|_| MplCoreError::InvalidOracleAccountData)?;

let oracle_data = (*oracle_account.data).borrow();
let mut oracle_data_slice = oracle_data
.get(offset..)
.ok_or(MplCoreError::InvalidOracleAccountData)?;

if oracle_data_slice.len() < OracleValidation::serialized_size() {
return Err(MplCoreError::InvalidOracleAccountData.into());
}

let validation_result = OracleValidation::deserialize(&mut oracle_data_slice)
.map_err(|_| MplCoreError::InvalidOracleAccountData)?;

match validation_result {
OracleValidation::V1 {
Expand Down Expand Up @@ -188,3 +197,10 @@ pub enum OracleValidation {
update: ExternalValidationResult,
},
}

impl OracleValidation {
/// Borsh- and Anchor-serialized size of the `OracleValidation` struct.
pub fn serialized_size() -> usize {
5
}
}

0 comments on commit 80178c4

Please sign in to comment.