Skip to content

Commit

Permalink
feat: add ceres initializer and docs
Browse files Browse the repository at this point in the history
  • Loading branch information
thepiwo committed Mar 6, 2024
1 parent 388f867 commit 0721822
Show file tree
Hide file tree
Showing 14 changed files with 231 additions and 18 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ npm install -g @aeternity/aeproject
- [Unit Testing](docs/cli/test.md)
- [AEproject Library](docs/lib.md)
- [Migration from 3.x.x to 4.x.x](docs/migration-from-3.x.x-to-4.x.x.md)
- [Upcoming Hard-Fork / Ceres Support](docs/ceres-support.md)

## Release Process

Expand Down
21 changes: 21 additions & 0 deletions docs/ceres-support.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Upcoming Hard-Fork / Ceres Support

Aeproject can already be used for testing and setup with the upcoming Ceres hard-fork.

### Automatic update

Use `aeproject init --next ` to initialize a new project that has the necessary adjustments for ceres applied.

Use `aeproject init --update --next` to update an existing project with the adjustments for ceres. For updating existing tests implemented change occurrences of `utils.getSdk()` to `utils.getSdk({ ignoreVersion: true })` or use the same option for manually initialized sdk `Node` and `CompilerHttp`.

### Manual update

- change occurrences of `utils.getSdk()` to `utils.getSdk({ ignoreVersion: true })` or use the same option for manually initialized sdk `Node` and `CompilerHttp`
- update `docker/aeternity.yml` to include
```yaml
chain:
hard_forks:
"1": 0
"6": 1
```
- update `docker-compose.yml` to use the `latest` node and compiler tags or specify it manually in running with `aeproject env --nodeVersion latest --compilerVersion latest`
4 changes: 4 additions & 0 deletions docs/cli/init.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,7 @@ aeproject init --update
```

Updates the project structure and needed artifacts to the latest version, as well as installing needed dependencies.

## Upcoming Hard-fork initialization

The additional parameter `--next` can be used to either initialize or update a project with changes for an upcoming hard-fork if available.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"lint:ci": "eslint --ext .js --max-warnings=0 .",
"test": "mocha ./tests/**/*.js --timeout 0 --exit",
"prepack": "npm run build:clean && npm run build",
"copy-files": "cp -r ./src/init/artifacts ./.build/cjs/src/init/ && cp -r ./src/init/artifacts ./.build/esm/src/init/ && cp -r ./src/init/update-artifacts ./.build/cjs/src/init/ && cp -r ./src/init/update-artifacts ./.build/esm/src/init/",
"copy-files": "cp -r ./src/init/artifacts ./.build/cjs/src/init/ && cp -r ./src/init/artifacts ./.build/esm/src/init/ && cp -r ./src/init/update-artifacts ./.build/cjs/src/init/ && cp -r ./src/init/update-artifacts ./.build/esm/src/init/ && cp -r ./src/init/next-artifacts ./.build/cjs/src/init/ && cp -r ./src/init/next-artifacts ./.build/esm/src/init/",
"link:local": "npm uninstall -g @aeternity/aeproject && npm run build:clean && npm run build && npm link"
},
"license": "ISC",
Expand Down
7 changes: 6 additions & 1 deletion src/cli/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,13 @@ const addInitOption = (program) => {
constants.artifactsDest,
)
.option("--update", "update project files")
.option(
"--next",
"apply patches to initialise or update for use with the upcoming release",
)
.option("-y", "overwrite all files in update process")
.action(async (folder, option) => {
await init.run(folder, option.update);
await init.run(folder, option.update, option.next, option.y);
});
};

Expand Down
1 change: 1 addition & 0 deletions src/init/constants.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"artifactsDest": "./",
"artifactsDir": "/artifacts",
"updateArtifactsDir": "/update-artifacts",
"nextArtifactsDir": "/next-artifacts",
"dependencies": ["@aeternity/aepp-sdk@13"],
"devDependencies": ["chai@4", "chai-as-promised@7", "mocha@10"],
"uninstallDependencies": ["aeproject", "aeproject-lib"],
Expand Down
27 changes: 20 additions & 7 deletions src/init/init.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,30 @@ const {
deleteWithPrompt,
} = require("../utils/fs-utils");

async function run(folder, update) {
async function run(folder, update, next, y) {
checkNodeVersion();
createFolder(folder);

if (update) {
await updateAEprojectProjectLibraries(folder, update);
await updateAEprojectProjectLibraries(folder, update, y);
} else {
await createAEprojectProjectStructure(folder);
}

// currently implements ceres patches, might be different in the future when ceres is the default
if (next) await patchForNextRelease(folder, y);
}

const patchForNextRelease = async (folder, y) => {
print(
"===== updating project file and directory structure for next version =====",
);

const fileSource = `${__dirname}${constants.nextArtifactsDir}`;

await copyFolderRecursiveSync(fileSource, folder, y);
};

const checkNodeVersion = () => {
if (parseInt(process.version.split(".")[0].replace("v", ""), 10) < 16) {
print("You need to use Node.js 16 or newer to use aeproject.");
Expand All @@ -49,10 +62,10 @@ const createAEprojectProjectStructure = async (folder) => {
);
};

const updateAEprojectProjectLibraries = async (folder, update) => {
const updateAEprojectProjectLibraries = async (folder, update, y) => {
print("===== updating aeproject =====");

await updateArtifacts(folder);
await updateArtifacts(folder, y);
await installDependencies(folder, update);

print("===== aeproject sucessfully initalized =====");
Expand Down Expand Up @@ -107,17 +120,17 @@ const setupArtifacts = async (folder) => {
);
};

const updateArtifacts = async (folder) => {
const updateArtifacts = async (folder, y) => {
print("===== updating project file and directory structure =====");

const fileSource = `${__dirname}${constants.updateArtifactsDir}`;

await constants.deleteArtifacts.reduce(async (promiseAcc, artifact) => {
await promiseAcc;
await deleteWithPrompt(artifact);
await deleteWithPrompt(artifact, y);
}, Promise.resolve());

await copyFolderRecursiveSync(fileSource, folder);
await copyFolderRecursiveSync(fileSource, folder, y);
};

module.exports = {
Expand Down
28 changes: 28 additions & 0 deletions src/init/next-artifacts/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
version: "3.6"
services:
aeproject_node:
image: aeternity/aeternity:${NODE_TAG:-latest}-bundle
hostname: node
environment:
AETERNITY_CONFIG: /home/aeternity/aeternity.yaml
AE__SYSTEM__CUSTOM_PREFUNDED_ACCS_FILE: "/home/aeternity/node/data/aecore/.genesis/accounts_test.json"
volumes:
- "./docker/aeternity.yaml:/home/aeternity/aeternity.yaml"
- "./docker/accounts.json:/home/aeternity/node/data/aecore/.genesis/accounts_test.json"

aeproject_compiler:
image: aeternity/aesophia_http:${COMPILER_TAG:-latest}
hostname: compiler
ports:
- "3080:3080"

aeproject_proxy:
image: nginx:latest
hostname: proxy
ports:
- "3001:3001"
volumes:
- "./docker/nginx.conf:/etc/nginx/conf.d/default.conf"
depends_on:
- aeproject_compiler
- aeproject_node
50 changes: 50 additions & 0 deletions src/init/next-artifacts/docker/aeternity.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
http:
external:
gas_limit: 60000000
internal:
debug_endpoints: true
listen_address: 0.0.0.0
endpoints:
dry-run: true

system:
plugin_path: /home/aeternity/node/plugins
plugins:
- name: aeplugin_dev_mode
config: # keeping the old config style at first to stay backwards compatible
keyblock_interval: 0
microblock_interval: 0
auto_emit_microblocks: true

dev_mode:
keyblock_interval: 0
microblock_interval: 0
auto_emit_microblocks: true

fork_management:
network_id: ae_dev

chain:
hard_forks:
"1": 0
"6": 1
persist: true
consensus:
"0":
name: "on_demand" # keeping the old config style at first to stay backwards compatible
type: "on_demand"

mining:
beneficiary: "ak_RdoCvwe7kxPu2VBv2gQAc1V81sGyTTuxFv36AcvNQYZN7qgut"
beneficiary_reward_delay: 2
strictly_follow_top: true

websocket:
channel:
port: 3014
listen_address: 0.0.0.0

logging:
# Controls the overload protection in the logs.
hwm: 50
level: debug
54 changes: 54 additions & 0 deletions src/init/next-artifacts/test/exampleTest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
const { assert } = require("chai");
const { utils } = require("@aeternity/aeproject");
const chaiAsPromised = require("chai-as-promised");
const chai = require("chai");

chai.use(chaiAsPromised);

const EXAMPLE_CONTRACT_SOURCE = "./contracts/ExampleContract.aes";

describe("ExampleContract", () => {
let aeSdk;
let contract;

before(async () => {
aeSdk = utils.getSdk({ ignoreVersion: true });

// a filesystem object must be passed to the compiler if the contract uses custom includes
const fileSystem = utils.getFilesystem(EXAMPLE_CONTRACT_SOURCE);

// get content of contract
const sourceCode = utils.getContractContent(EXAMPLE_CONTRACT_SOURCE);

// initialize the contract instance
contract = await aeSdk.initializeContract({ sourceCode, fileSystem });
await contract.init();

// create a snapshot of the blockchain state
await utils.createSnapshot(aeSdk);
});

// after each test roll back to initial state
afterEach(async () => {
await utils.rollbackSnapshot(aeSdk);
});

it("ExampleContract: set and get", async () => {
const set = await contract.set(42, {
onAccount: utils.getDefaultAccounts()[1],
});
assert.equal(set.decodedEvents[0].name, "SetXEvent");
assert.equal(
set.decodedEvents[0].args[0],
utils.getDefaultAccounts()[1].address,
);
assert.equal(set.decodedEvents[0].args[1], 42);

const { decodedResult } = await contract.get();
assert.equal(decodedResult, 42);
});

it("ExampleContract: get undefined when not set before", async () => {
await assert.isRejected(contract.get(), "NOTHING_SET_YET");
});
});
6 changes: 3 additions & 3 deletions src/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,13 @@ export function getDefaultAccounts(): MemoryAccount[] {
return wallets.map((keypair) => new MemoryAccount(keypair.secretKey));
}

export function getSdk(): AeSdk {
const instance = new Node(networks.devmode.nodeUrl, { ignoreVersion: true });
export function getSdk(options: {}): AeSdk {
const instance = new Node(networks.devmode.nodeUrl, options);

return new AeSdk({
accounts: getDefaultAccounts(),
nodes: [{ name: "node", instance }],
onCompiler: new CompilerHttp(networks.devmode.compilerUrl),
onCompiler: new CompilerHttp(networks.devmode.compilerUrl, options),
interval: 50,
});
}
Expand Down
10 changes: 5 additions & 5 deletions src/utils/fs-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ async function prompt(action, target) {
return input === "YES" || input === "yes" || input === "Y" || input === "y";
}

async function copyFolderRecursiveSync(srcDir, dstDir) {
async function copyFolderRecursiveSync(srcDir, dstDir, y = false) {
let src;
let dst;

Expand All @@ -28,18 +28,18 @@ async function copyFolderRecursiveSync(srcDir, dstDir) {
fs.mkdirSync(dst);
}

await copyFolderRecursiveSync(src, dst);
await copyFolderRecursiveSync(src, dst, y);
} else if (!fs.existsSync(dst)) {
fs.writeFileSync(dst, fs.readFileSync(src));
} else if (await prompt("overwrite", dst)) {
} else if (y || (await prompt("overwrite", dst))) {
fs.writeFileSync(dst, fs.readFileSync(src));
}
}, Promise.resolve());
}

async function deleteWithPrompt(target) {
async function deleteWithPrompt(target, y = false) {
if (fs.existsSync(target)) {
if (await prompt("delete", target)) {
if (y || (await prompt("delete", target))) {
fs.rmSync(target, { recursive: true });
}
}
Expand Down
35 changes: 35 additions & 0 deletions tests/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,41 @@ describe("command line usage", () => {
assert.include(res.stdout, "2 passing");
});

it("init --update --next", async () => {
const res = await exec("aeproject init --update --next -y", { cwd });
assert.equal(res.code, 0);
assert.equal(res.stderr, "");
assert.include(
res.stdout,
"===== updating project file and directory structure =====",
);
assert.include(
res.stdout,
"===== updating project file and directory structure for next version =====",
);

assert.include(file(path.join(cwd, "docker/aeternity.yaml")), "hard_forks");
assert.include(
file(path.join(cwd, "test/exampleTest.js")),
"ignoreVersion: true",
);
assert.include(
file(path.join(cwd, "docker-compose.yml")),
"COMPILER_TAG:-latest",
);
assert.include(
file(path.join(cwd, "docker-compose.yml")),
"NODE_TAG:-latest",
);

const resEnv = await exec("aeproject env", { cwd });
assert.equal(resEnv.code, 0);
assert.isTrue(await isEnvRunning(cwd));

assert.include(resEnv.stdout, "aeternity/aeternity latest-bundle");
assert.include(resEnv.stdout, "aeternity/aesophia_http latest");
});

it("env --stop", async () => {
const res = await exec("aeproject env --stop", { cwd });
assert.equal(res.code, 0);
Expand Down
3 changes: 2 additions & 1 deletion tests/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ async function exec(cmd, options) {
}

async function prepareLocal() {
cleanLocal();
await exec("npm run link:local");
if (!fs.existsSync(cwd)) fs.mkdirSync(cwd);
}

function cleanLocal() {
fs.rmSync(cwd, { recursive: true });
if (fs.existsSync(cwd)) fs.rmSync(cwd, { recursive: true });
}

async function linkLocalLib(folder) {
Expand Down

0 comments on commit 0721822

Please sign in to comment.