Skip to content

Commit

Permalink
Merge pull request #4 from ChainSafe/publish
Browse files Browse the repository at this point in the history
Add install scripts
  • Loading branch information
dapplion authored Nov 17, 2020
2 parents ccb6116 + c2821e2 commit 5dff673
Show file tree
Hide file tree
Showing 14 changed files with 321 additions and 25 deletions.
90 changes: 86 additions & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,47 @@
name: Test
on: [push, pull_request]

on:
pull_request:
push:
branches:
- "**"
tags:
- "v*.*.*"

jobs:
build-swig:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
submodules: true
- name: Setup SWIG
run: |
git clone -b pr/new-node-fixes https://github.com/yegorich/swig;
cd swig;
./autogen.sh;
./configure --prefix=$HOME/swig;
make;
make install;
- name: Run.me
run: |
env PATH=~/swig/bin:$PATH SWIG_LIB=~/swig/share/swig/4.0.2 \
./blst/bindings/node.js/run.me
- name: Upload binding.node
uses: actions/upload-artifact@v2
with:
name: blst_wrap.cpp
path: blst/bindings/node.js/blst_wrap.cpp

build:
needs: ["build-swig"]
runs-on: ${{matrix.os}}
strategy:
fail-fast: false
matrix:
# windows-latest disabled by now, unable to build
os: [ubuntu-latest, macos-latest]
node: [12, 14]
node: [10, 11, 12, 13, 14]
steps:
- uses: actions/checkout@v2
with:
Expand All @@ -17,7 +50,56 @@ jobs:
uses: actions/setup-node@v1
with:
node-version: ${{matrix.node}}
- name: Install & Build
run: yarn install

- name: Get SWIG pre-built
uses: actions/download-artifact@v2
with:
name: blst_wrap.cpp
path: prebuild

- name: Install && Build TS + bindings
run: yarn bootstrap
- name: Test
run: yarn test

- name: Upload binding.node
uses: actions/upload-artifact@v2
if: github.repository_owner == 'chainsafe' && github.event_name != 'pull_request'
with:
name: binding.node
path: build/

publish:
needs: ["build-swig", "build"]
if: startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
submodules: true
- name: Get SWIG pre-built
uses: actions/download-artifact@v2
with:
name: blst_wrap.cpp
path: prebuild
- name: Get binding.node pre-builts
uses: actions/download-artifact@v2
with:
name: binding.node
path: prebuild

- name: Install && Build TS + bindings
run: yarn bootstrap

- name: Create Github release with prebuilds
uses: softprops/action-gh-release@v1
with:
files: prebuild/*
fail_on_unmatched_files: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

# - name: Publish to NPM
# run: npm publish --access public
# env:
# NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ node_modules
prebuilds

npm-debug.log
yarn-error.log
yarn-error.log
8 changes: 4 additions & 4 deletions build.node.sh
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
#!/bin/sh -e

BLST_WRAP_PREBUILD=blst_wrap.cpp
BLST_WRAP_OUTPUT=blst/bindings/node.js
BLST_NODE_OUTPUT=blst/bindings/node.js/blst.node
BLST_NODE_TARGET=dist/blst.node

cp $BLST_WRAP_PREBUILD $BLST_WRAP_OUTPUT
# Copy SWIG prebuilt
cp blst_wrap.cpp blst/bindings/node.js

(cd blst/bindings/node.js; ./run.me)
# Build node bindings
./blst/bindings/node.js/run.me

mkdir -p `dirname $BLST_NODE_TARGET`
cp $BLST_NODE_OUTPUT $BLST_NODE_TARGET
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@
"dist"
],
"scripts": {
"install": "./build.node.sh",
"install": "node dist/scripts/install.js",
"test": "mocha test/**/*",
"build": "tsc"
"build": "tsc",
"bootstrap": "yarn install --ignore-scripts && yarn build && yarn install"
},
"repository": {
"type": "git",
Expand Down
File renamed without changes.
3 changes: 2 additions & 1 deletion src/bindings.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export const blst: Blst = require("../build/blst");
import { getBinaryPath } from "./scripts/paths";
export const blst: Blst = require(getBinaryPath());

export interface Blst {
SecretKey: SecretKeyConstructor;
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./lib";
25 changes: 12 additions & 13 deletions src/lib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,25 +162,29 @@ export class AggregateSignature {
}
}

export function verify(msg: Uint8Array, pk: PublicKey, sig: Signature): void {
aggregateVerify([msg], [pk], sig);
export function verify(
msg: Uint8Array,
pk: PublicKey,
sig: Signature
): boolean {
return aggregateVerify([msg], [pk], sig);
}

export function fastAggregateVerify(
msg: Uint8Array,
pks: PublicKey[],
sig: Signature
): void {
): boolean {
const aggPk = AggregatePublicKey.fromPublicKeys(pks);
const pk = aggPk.toPublicKey();
aggregateVerify([msg], [pk], sig);
return aggregateVerify([msg], [pk], sig);
}

export function aggregateVerify(
msgs: Uint8Array[],
pks: PublicKey[],
sig: Signature
): void {
): boolean {
const n_elems = pks.length;
if (msgs.length !== n_elems) {
throw new ErrorBLST(BLST_ERROR.BLST_VERIFY_FAIL);
Expand All @@ -198,17 +202,15 @@ export function aggregateVerify(

// PT constructor calls `blst_aggregated`
const gtsig = new blst.PT(sig.value);
if (!ctx.finalverify(gtsig)) {
throw new ErrorBLST(BLST_ERROR.BLST_VERIFY_FAIL);
}
return ctx.finalverify(gtsig);
}

// https://ethresear.ch/t/fast-verification-of-multiple-bls-signatures/5407
export function verifyMultipleAggregateSignatures(
msgs: Uint8Array[],
pks: PublicKey[],
sigs: Signature[]
): void {
): boolean {
const n_elems = pks.length;
if (msgs.length !== n_elems || sigs.length !== n_elems) {
throw new ErrorBLST(BLST_ERROR.BLST_VERIFY_FAIL);
Expand All @@ -230,8 +232,5 @@ export function verifyMultipleAggregateSignatures(
}

ctx.commit();

if (!ctx.finalverify()) {
throw new ErrorBLST(BLST_ERROR.BLST_VERIFY_FAIL);
}
return ctx.finalverify();
}
40 changes: 40 additions & 0 deletions src/scripts/buildBindings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import fs from "fs";
import { exec } from "child_process";
import { testBindings } from "./testBindings";
import {
bindingsDirSrc,
bindingsSrc,
ensureDirFromFilepath,
prebuiltSwigSrc,
prebuiltSwigTarget,
} from "./paths";

export async function buildBindings(binaryPath: string) {
// Copy SWIG prebuilt
fs.copyFileSync(prebuiltSwigSrc, prebuiltSwigTarget);

// Use BLST run.me script to build libblst.a + blst.node
await new Promise((resolve, reject): void => {
const proc = exec(
"./run.me",
{
timeout: 3 * 60 * 1000, // ms
maxBuffer: 10e6, // bytes
cwd: bindingsDirSrc,
},
(err, stdout, stderr) => {
if (err) reject(err);
else resolve(stdout.trim() || stderr);
}
);
if (proc.stdout) proc.stdout.pipe(process.stdout);
if (proc.stderr) proc.stderr.pipe(process.stderr);
});

// Copy built .node file to expected path
ensureDirFromFilepath(binaryPath);
fs.copyFileSync(bindingsSrc, binaryPath);

// Make sure downloaded bindings work
await testBindings(binaryPath);
}
20 changes: 20 additions & 0 deletions src/scripts/downloadBindings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { testBindings } from "./testBindings";
import { download } from "./downloadFile";
import { ensureDirFromFilepath, getBinaryName, packageJsonPath } from "./paths";

const githubReleasesDownloadUrl =
"https://github.com/ChainSafe/blst-ts/releases/download";

export async function checkAndDownloadBinary(binaryPath: string) {
const packageJson = require(packageJsonPath);
const binaryName = getBinaryName();
const version = packageJson.version;

const binaryUrl = `${githubReleasesDownloadUrl}/v${version}/${binaryName}`;

ensureDirFromFilepath(binaryPath);
await download(binaryUrl, binaryPath);

// Make sure downloaded bindings work
await testBindings(binaryPath);
}
47 changes: 47 additions & 0 deletions src/scripts/downloadFile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import fs from "fs";
import https from "https";

export class HttpError extends Error {
statusCode?: number;
constructor(message: string, statusCode?: number) {
super(message);
this.statusCode = statusCode;
}
}

/**
* Downloads file from remote HTTP[S] host and puts its contents to the
* specified location.
*/
export function download(url: string, filePath: string): Promise<void> {
return new Promise((resolve, reject) => {
const file = fs.createWriteStream(filePath);

const request = https.get(url, (response) => {
if (response.statusCode !== 200) {
reject(
new HttpError(
`Failed to get '${url}' (${response.statusCode})`,
response.statusCode
)
);
return;
}

response.pipe(file);
});

// The destination stream is ended by the time it's called
file.on("finish", () => resolve());

request.on("error", (err) => {
fs.unlink(filePath, () => reject(err));
});

file.on("error", (err) => {
fs.unlink(filePath, () => reject(err));
});

request.end();
});
}
60 changes: 60 additions & 0 deletions src/scripts/install.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import fs from "fs";
import { checkAndDownloadBinary } from "./downloadBindings";
import { buildBindings } from "./buildBindings";
import { getBinaryPath } from "./paths";
import { testBindings } from "./testBindings";

const libName = "BLST native bindings";

// CLI runner
install().then(
() => process.exit(0),
(e) => {
console.log(e.stack);
process.exit(1);
}
);

async function install() {
const binaryPath = getBinaryPath();

// Check if bindings already downloaded or built
if (fs.existsSync(binaryPath)) {
try {
await testBindings(binaryPath);
console.log(`Using existing ${libName} from ${binaryPath}`);
return;
} catch (e) {
console.log(`Cached ${libName} not OK`);
}
}

// Fetch pre-built bindings from remote repo
try {
console.log(`Retrieving ${libName}...`);
await checkAndDownloadBinary(binaryPath);
await testBindings(binaryPath);
console.log(`Successfully retrieved ${libName}`);
return;
} catch (e) {
if (e.statusCode === 404) {
console.error(`${libName} not available: ${e.message}`);
} else {
console.error(`Error importing ${libName}: ${e.stack}`);
}
}

// Build bindings locally from source
try {
console.log(`Building ${libName} from source...`);
await buildBindings(binaryPath);
await testBindings(binaryPath);
console.log(`Successfully built ${libName} from source`);
return;
} catch (e) {
console.error(`Error building ${libName}: ${e.stack}`);
}

// Fallback?
throw Error(`Error downloading and building ${libName}. No fallback`);
}
Loading

0 comments on commit 5dff673

Please sign in to comment.