Skip to content

Commit

Permalink
refactor website uploader contract
Browse files Browse the repository at this point in the history
  • Loading branch information
peterjah committed Sep 7, 2023
1 parent 6eadc45 commit 155404f
Show file tree
Hide file tree
Showing 12 changed files with 267 additions and 215 deletions.
1 change: 0 additions & 1 deletion smart-contracts/assembly/contracts/NFT/NFT.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
stringToBytes,
bytesToU256,
u256ToBytes,
boolToByte,
u32ToBytes,
} from '@massalabs/as-types';
import { u256 } from 'as-bignum/assembly';
Expand Down
2 changes: 0 additions & 2 deletions smart-contracts/assembly/contracts/NFT/__tests__/NFT.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ import { u256 } from 'as-bignum/assembly';

const callerAddress = 'A12UBnqTHDQALpocVBnkPNy7y5CndUJQTLutaVDDFgMJcq5kQiKq';

const userAddress = 'A12BqZEQ6sByhRLyEuf0YbQmcF2PsDdkNNG1akBJu9XcjZA1e8';

const NFTName = 'MASSA_NFT';
const NFTSymbol = 'NFT';
const NFTBaseURI = 'my.massa/';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
import { Args, boolToByte, stringToBytes } from '@massalabs/as-types';
import { Storage, changeCallStack } from '@massalabs/massa-as-sdk';
import {
OWNER_KEY,
isOwner,
onlyOwner,
ownerAddress,
setOwner,
} from '../ownership';
import { isOwner, onlyOwner, ownerAddress, setOwner } from '../ownership';

import { resetStorage } from '@massalabs/massa-as-sdk';
import { OWNER_KEY } from '../ownership-internal';

// address of the contract set in vm-mock. must match with contractAddr of @massalabs/massa-as-sdk/vm-mock/vm.js
const contractAddr = 'AS12BqZEQ6sByhRLyEuf0YbQmcF2PsDdkNNG1akBJu9XcjZA1eT';
Expand Down
3 changes: 2 additions & 1 deletion smart-contracts/assembly/contracts/utils/accessControl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import {
Context,
} from '@massalabs/massa-as-sdk';
import { Args, boolToByte } from '@massalabs/as-types';
import { _isOwner, onlyOwner } from './ownership';
import { onlyOwner } from './ownership';
import { _hasRole, _members, _roleKey } from './accessControl-internal';
import { _isOwner } from './ownership-internal';

export const ROLES_KEY = '_ROLES';

Expand Down
50 changes: 50 additions & 0 deletions smart-contracts/assembly/contracts/utils/ownership-internal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import {
Context,
Storage,
createEvent,
generateEvent,
} from '@massalabs/massa-as-sdk';

export const OWNER_KEY = 'OWNER';

export const CHANGE_OWNER_EVENT_NAME = 'CHANGE_OWNER';

/**
* Sets the contract owner. This function is to be called from a smart contract.
*
* @param newOwner - The address of the new contract owner.
*
* Emits a CHANGE_OWNER event upon successful execution.
*/
export function _setOwner(newOwner: string): void {
if (Storage.has(OWNER_KEY)) {
_onlyOwner();
}
Storage.set(OWNER_KEY, newOwner);

generateEvent(createEvent(CHANGE_OWNER_EVENT_NAME, [newOwner]));
}

/**
* Checks if the given account is the owner of the contract.
*
* @param account - The address of the account to check.
* @returns true if the account is the owner, false otherwise.
*/
export function _isOwner(account: string): bool {
if (!Storage.has(OWNER_KEY)) {
return false;
}
return account === Storage.get(OWNER_KEY);
}

/**
* Check if the caller is the contract owner.
*
* @throws Will throw an error if the caller is not the owner or if the owner is not set.
*/
export function _onlyOwner(): void {
assert(Storage.has(OWNER_KEY), 'Owner is not set');
const owner = Storage.get(OWNER_KEY);
assert(Context.caller().toString() === owner, 'Caller is not the owner');
}
36 changes: 10 additions & 26 deletions smart-contracts/assembly/contracts/utils/ownership.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,26 @@
import {
Context,
generateEvent,
Storage,
createEvent,
} from '@massalabs/massa-as-sdk';
import { Storage } from '@massalabs/massa-as-sdk';
import { Args, boolToByte, stringToBytes } from '@massalabs/as-types';

export const OWNER_KEY = 'OWNER';

export const CHANGE_OWNER_EVENT_NAME = 'CHANGE_OWNER';
import {
OWNER_KEY,
_isOwner,
_onlyOwner,
_setOwner,
} from './ownership-internal';

/**
* Set the contract owner
*
* @param binaryArgs - byte string with the following format:
* - the address of the new contract owner (address).
*/

export function setOwner(binaryArgs: StaticArray<u8>): void {
const args = new Args(binaryArgs);
const newOwner = args
.nextString()
.expect('newOwnerAddress argument is missing or invalid');

if (Storage.has(OWNER_KEY)) {
onlyOwner();
}
Storage.set(OWNER_KEY, newOwner);

generateEvent(createEvent(CHANGE_OWNER_EVENT_NAME, [newOwner]));
_setOwner(newOwner);
}

/**
Expand Down Expand Up @@ -58,20 +51,11 @@ export function isOwner(binaryArgs: StaticArray<u8>): StaticArray<u8> {
return boolToByte(_isOwner(address));
}

export function _isOwner(account: string): bool {
if (!Storage.has(OWNER_KEY)) {
return false;
}
return account === Storage.get(OWNER_KEY);
}

/**
* Throws if the caller is not the owner.
*
* @param address -
*/
export function onlyOwner(): void {
assert(Storage.has(OWNER_KEY), 'Owner is not set');
const owner = Storage.get(OWNER_KEY);
assert(Context.caller().toString() === owner, 'Caller is not the owner');
_onlyOwner();
}
Original file line number Diff line number Diff line change
@@ -1,30 +1,93 @@
import { Args } from '@massalabs/as-types';
import { Storage } from '@massalabs/massa-as-sdk';
import { Args, i32ToBytes, unwrapStaticArray } from '@massalabs/as-types';
import {
Storage,
resetStorage,
setDeployContext,
} from '@massalabs/massa-as-sdk';
import {
NB_CHUNKS_KEY,
appendBytesToWebsite,
initializeWebsite,
keyExpectedNbChunks,
} from '../websiteDeployer';
constructor,
deleteWebsite,
} from '../websiteStorer';
import { isOwner } from '../../utils';

const user = 'AU12UBnqTHDQALpocVBnkPNy7y5CndUJQTLutaVDDFgMJcq5kQiKq';

describe('website deployer tests', () => {
test('initializeWebsite', () => {
// execute
const value: u64 = 52;
beforeAll(() => {
resetStorage();
setDeployContext(user);

constructor([]);
});

test('owner is set', () => {
expect(isOwner(new Args().add(user).serialize())).toBeTruthy();
});

throws('delete fails if website not created', () => {
const chunkId = i32(0);
const data = new Uint8Array(100);
data.fill(0xf);
deleteWebsite(new Args().add(chunkId).add(data).serialize());
});

test('upload a website', () => {
const nbChunks = 20;

initializeWebsite(new Args().add(value).serialize());
// assert
expect(Storage.get(keyExpectedNbChunks).nextU64().unwrap()).toBe(value);
for (let chunkId: i32 = 0; chunkId < nbChunks; chunkId++) {
const data = new Uint8Array(100);
data.fill(chunkId & 0xf);
const argsAppend = new Args().add(chunkId).add(data).serialize();
appendBytesToWebsite(argsAppend);

expect(Storage.get(NB_CHUNKS_KEY)).toStrictEqual(i32ToBytes(chunkId + 1));
expect(Storage.get(i32ToBytes(chunkId))).toStrictEqual(
unwrapStaticArray(data),
);
}

expect(Storage.get(NB_CHUNKS_KEY)).toStrictEqual(i32ToBytes(nbChunks));
});

test('edit a website (upload missed chunks)', () => {
const nbChunks = 15;
for (let chunkId: i32 = 0; chunkId < nbChunks; chunkId++) {
const data = new Uint8Array(100);
data.fill(chunkId & 0xf);
const argsAppend = new Args().add(chunkId).add(data).serialize();
appendBytesToWebsite(argsAppend);

expect(Storage.get(i32ToBytes(chunkId))).toStrictEqual(
unwrapStaticArray(data),
);
}
});

test('append to website', () => {
const chunkId = u64(5);
const want = new Uint8Array(2);
want.set([0, 1]);
const MASSA_WEB_CHUNKS = `massa_web_${chunkId}`;
const MASSA_WEB_CHUNKS_ARR = new Args().add(MASSA_WEB_CHUNKS).serialize();
const argsAppend = new Args().add(chunkId).add(want).serialize();
appendBytesToWebsite(argsAppend);
const got = new Args(Storage.get(MASSA_WEB_CHUNKS_ARR)).nextUint8Array();
expect(got.unwrap()).toStrictEqual(want);
test('delete website', () => {
deleteWebsite([]);
expect(Storage.has(NB_CHUNKS_KEY)).toBeFalsy();
const nbChunks = 20;
for (let chunkId: i32 = 0; chunkId < nbChunks; chunkId++) {
expect(Storage.has(i32ToBytes(chunkId))).toBeFalsy();
}
});

test('update website', () => {
const nbChunks = 9;
for (let chunkId: i32 = 0; chunkId < nbChunks; chunkId++) {
const data = new Uint8Array(100);
data.fill(chunkId & 0xf);
const argsAppend = new Args().add(chunkId).add(data).serialize();
appendBytesToWebsite(argsAppend);

expect(Storage.get(NB_CHUNKS_KEY)).toStrictEqual(i32ToBytes(chunkId + 1));
expect(Storage.get(i32ToBytes(chunkId))).toStrictEqual(
unwrapStaticArray(data),
);
}

expect(Storage.get(NB_CHUNKS_KEY)).toStrictEqual(i32ToBytes(nbChunks));
});
});

This file was deleted.

Loading

0 comments on commit 155404f

Please sign in to comment.