Compare commits
102 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 95077ed429 | |||
| 05e6cc8c18 | |||
| 5caf5833ad | |||
| ed854f2bbd | |||
| e3976b8dc1 | |||
| 02c43ca656 | |||
| 1ec98976b1 | |||
| 93833b8e03 | |||
| d6cd2c9a7d | |||
| ae2679e164 | |||
| 0f25eaa33a | |||
| b7b4554a18 | |||
| 20e59a92bc | |||
| 31fd1361aa | |||
| 449f37133b | |||
| feeee5eb8f | |||
| 32de87b185 | |||
| 78dd785035 | |||
| f4b39ea29e | |||
| 20f45e5923 | |||
| fc2166a46d | |||
| 39a5ba846a | |||
| e4b28a7854 | |||
| e4819c35e1 | |||
| 7b7027cbee | |||
| 74fb1615d8 | |||
| 5523010cfd | |||
| 7c106605cc | |||
| 9047d1175b | |||
| da6a068639 | |||
| a886743005 | |||
| 0dbfb1a6ed | |||
| 9d1ea27ed7 | |||
| 71548a6425 | |||
| 72c5d299fe | |||
| 5cf31c9929 | |||
| 941b525093 | |||
| e377339f04 | |||
| fcbdb0ae98 | |||
| ecc5c4ec11 | |||
| caa01ca443 | |||
| 3e585d0f8a | |||
| 967ab869e0 | |||
| 0d977585ce | |||
| a357765c73 | |||
| 280d799958 | |||
| f694588f9f | |||
| 26025d7382 | |||
| 517ef20396 | |||
| 6f16383453 | |||
| debba62dd8 | |||
| 343596a0c1 | |||
| ec27d3d1f3 | |||
| f347ab534e | |||
| 3db765e0f1 | |||
| 0dbd5cf68c | |||
| da2a1dc996 | |||
| 78973e4088 | |||
| d627a18e8e | |||
| be7fc5714e | |||
| 2d6307b37e | |||
| 3d77eb001b | |||
| ef9b3ea1b6 | |||
| 943d113480 | |||
| 34b185d49b | |||
| 79e99ad605 | |||
| 6c9012874b | |||
| 278b94baf7 | |||
| 20b1da2b47 | |||
| 82ef97bf4e | |||
| cca0dc306e | |||
| 897edb9d9f | |||
| f7c6b63cf7 | |||
| 32d7d9f9fd | |||
| 97737fdd86 | |||
| 7a5930bb66 | |||
| 51d9cc22d7 | |||
| ee1b184428 | |||
| d34c40bd68 | |||
| a3bf1f54a1 | |||
| 9b5ec62e19 | |||
| 453e5d0975 | |||
| 8f12805b4c | |||
| 9b1401aa4a | |||
| b3391af3bf | |||
| d0d7fa798b | |||
| 7468dede46 | |||
| 43d45edb01 | |||
| 76a341e52c | |||
| b0ea27b449 | |||
| 16c8021e93 | |||
| 266175a940 | |||
| 1bd84d8447 | |||
| 40a7e34d14 | |||
| 82829648ba | |||
| e63482a75e | |||
| 8027ecb367 | |||
| 1f44c07cd8 | |||
| 0103412fe7 | |||
| 051f8fd186 | |||
| 57b0acb59c | |||
| 2c4d19902c |
@@ -1,14 +0,0 @@
|
||||
name: 'Parallel ctest'
|
||||
description: 'Runs a set of labeled ctests in parallel via multiple docker containers'
|
||||
inputs:
|
||||
container:
|
||||
required: true
|
||||
error-log-paths:
|
||||
required: true
|
||||
log-tarball-prefix:
|
||||
required: true
|
||||
tests-label:
|
||||
required: true
|
||||
runs:
|
||||
using: 'node16'
|
||||
main: 'dist/index.mjs'
|
||||
File diff suppressed because one or more lines are too long
@@ -1,69 +0,0 @@
|
||||
import child_process from 'node:child_process';
|
||||
import process from 'node:process';
|
||||
import stream from 'node:stream';
|
||||
import fs from 'node:fs';
|
||||
import zlib from 'node:zlib';
|
||||
import tar from 'tar-stream';
|
||||
import core from '@actions/core'
|
||||
|
||||
const container = core.getInput('container', {required: true});
|
||||
const error_log_paths = JSON.parse(core.getInput('error-log-paths', {required: true}));
|
||||
const log_tarball_prefix = core.getInput('log-tarball-prefix', {required: true});
|
||||
const tests_label = core.getInput('tests-label', {required: true});
|
||||
|
||||
try {
|
||||
if(child_process.spawnSync("docker", ["run", "--name", "base", "-v", `${process.cwd()}/build.tar.zst:/build.tar.zst`, "--workdir", "/__w/leap/leap", container, "sh", "-c", "zstdcat /build.tar.zst | tar x"], {stdio:"inherit"}).status)
|
||||
throw new Error("Failed to create base container");
|
||||
if(child_process.spawnSync("docker", ["commit", "base", "baseimage"], {stdio:"inherit"}).status)
|
||||
throw new Error("Failed to create base image");
|
||||
if(child_process.spawnSync("docker", ["rm", "base"], {stdio:"inherit"}).status)
|
||||
throw new Error("Failed to remove base container");
|
||||
|
||||
// the correct approach is by far "--show-only=json-v1" and then pluck out .tests[].name; but that doesn't work on U18's cmake 3.10 since it lacks json-v1 output
|
||||
const test_query_result = child_process.spawnSync("docker", ["run", "--rm", "baseimage", "bash", "-e", "-o", "pipefail", "-c", `cd build; ctest -L '${tests_label}' --show-only | head -n -1 | cut -d ':' -f 2 -s | jq -cnR '[inputs | select(length>0)[1:]]'`]);
|
||||
if(test_query_result.status)
|
||||
throw new Error("Failed to discover tests with label")
|
||||
const tests = JSON.parse(test_query_result.stdout);
|
||||
|
||||
let subprocesses = [];
|
||||
tests.forEach(t => {
|
||||
subprocesses.push(new Promise(resolve => {
|
||||
child_process.spawn("docker", ["run", "--name", t, "--init", "baseimage", "bash", "-c", `cd build; ctest --output-on-failure -R '^${t}$'`], {stdio:"inherit"}).on('close', code => resolve(code));
|
||||
}));
|
||||
});
|
||||
|
||||
const results = await Promise.all(subprocesses);
|
||||
|
||||
for(let i = 0; i < results.length; ++i) {
|
||||
if(results[i] === 0)
|
||||
continue;
|
||||
|
||||
//failing test
|
||||
core.setFailed("Some tests failed");
|
||||
|
||||
let extractor = tar.extract();
|
||||
let packer = tar.pack();
|
||||
|
||||
extractor.on('entry', (header, stream, next) => {
|
||||
if(!header.name.startsWith(`__w/leap/leap/build`)) {
|
||||
stream.on('end', () => next());
|
||||
stream.resume();
|
||||
return;
|
||||
}
|
||||
|
||||
header.name = header.name.substring(`__w/leap/leap/`.length);
|
||||
if(header.name !== "build/" && error_log_paths.filter(p => header.name.startsWith(p)).length === 0) {
|
||||
stream.on('end', () => next());
|
||||
stream.resume();
|
||||
return;
|
||||
}
|
||||
|
||||
stream.pipe(packer.entry(header, next));
|
||||
}).on('finish', () => {packer.finalize()});
|
||||
|
||||
child_process.spawn("docker", ["export", tests[i]]).stdout.pipe(extractor);
|
||||
stream.promises.pipeline(packer, zlib.createGzip(), fs.createWriteStream(`${log_tarball_prefix}-${tests[i]}-logs.tar.gz`));
|
||||
}
|
||||
} catch(e) {
|
||||
core.setFailed(`Uncaught exception ${e.message}`);
|
||||
}
|
||||
@@ -1,351 +0,0 @@
|
||||
{
|
||||
"name": "parallel-ctest-containers",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.9.1",
|
||||
"@vercel/ncc": "^0.34.0",
|
||||
"tar-stream": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@actions/core": {
|
||||
"version": "1.9.1",
|
||||
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz",
|
||||
"integrity": "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==",
|
||||
"dependencies": {
|
||||
"@actions/http-client": "^2.0.1",
|
||||
"uuid": "^8.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@actions/http-client": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz",
|
||||
"integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==",
|
||||
"dependencies": {
|
||||
"tunnel": "^0.0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@vercel/ncc": {
|
||||
"version": "0.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.34.0.tgz",
|
||||
"integrity": "sha512-G9h5ZLBJ/V57Ou9vz5hI8pda/YQX5HQszCs3AmIus3XzsmRn/0Ptic5otD3xVST8QLKk7AMk7AqpsyQGN7MZ9A==",
|
||||
"bin": {
|
||||
"ncc": "dist/ncc/cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/base64-js": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/bl": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
|
||||
"integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
|
||||
"dependencies": {
|
||||
"buffer": "^5.5.0",
|
||||
"inherits": "^2.0.4",
|
||||
"readable-stream": "^3.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.1.13"
|
||||
}
|
||||
},
|
||||
"node_modules/end-of-stream": {
|
||||
"version": "1.4.4",
|
||||
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
|
||||
"integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
|
||||
"dependencies": {
|
||||
"once": "^1.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fs-constants": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
|
||||
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="
|
||||
},
|
||||
"node_modules/ieee754": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||
},
|
||||
"node_modules/once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||
"dependencies": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/readable-stream": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
|
||||
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/string_decoder": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
|
||||
"dependencies": {
|
||||
"safe-buffer": "~5.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tar-stream": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
|
||||
"integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
|
||||
"dependencies": {
|
||||
"bl": "^4.0.3",
|
||||
"end-of-stream": "^1.4.1",
|
||||
"fs-constants": "^1.0.0",
|
||||
"inherits": "^2.0.3",
|
||||
"readable-stream": "^3.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/tunnel": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
|
||||
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==",
|
||||
"engines": {
|
||||
"node": ">=0.6.11 <=0.7.0 || >=0.7.3"
|
||||
}
|
||||
},
|
||||
"node_modules/util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
||||
"bin": {
|
||||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@actions/core": {
|
||||
"version": "1.9.1",
|
||||
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz",
|
||||
"integrity": "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==",
|
||||
"requires": {
|
||||
"@actions/http-client": "^2.0.1",
|
||||
"uuid": "^8.3.2"
|
||||
}
|
||||
},
|
||||
"@actions/http-client": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz",
|
||||
"integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==",
|
||||
"requires": {
|
||||
"tunnel": "^0.0.6"
|
||||
}
|
||||
},
|
||||
"@vercel/ncc": {
|
||||
"version": "0.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.34.0.tgz",
|
||||
"integrity": "sha512-G9h5ZLBJ/V57Ou9vz5hI8pda/YQX5HQszCs3AmIus3XzsmRn/0Ptic5otD3xVST8QLKk7AMk7AqpsyQGN7MZ9A=="
|
||||
},
|
||||
"base64-js": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
|
||||
},
|
||||
"bl": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
|
||||
"integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
|
||||
"requires": {
|
||||
"buffer": "^5.5.0",
|
||||
"inherits": "^2.0.4",
|
||||
"readable-stream": "^3.4.0"
|
||||
}
|
||||
},
|
||||
"buffer": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
|
||||
"requires": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.1.13"
|
||||
}
|
||||
},
|
||||
"end-of-stream": {
|
||||
"version": "1.4.4",
|
||||
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
|
||||
"integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
|
||||
"requires": {
|
||||
"once": "^1.4.0"
|
||||
}
|
||||
},
|
||||
"fs-constants": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
|
||||
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="
|
||||
},
|
||||
"ieee754": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||
},
|
||||
"once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
|
||||
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
|
||||
"requires": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
|
||||
"requires": {
|
||||
"safe-buffer": "~5.2.0"
|
||||
}
|
||||
},
|
||||
"tar-stream": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
|
||||
"integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
|
||||
"requires": {
|
||||
"bl": "^4.0.3",
|
||||
"end-of-stream": "^1.4.1",
|
||||
"fs-constants": "^1.0.0",
|
||||
"inherits": "^2.0.3",
|
||||
"readable-stream": "^3.1.1"
|
||||
}
|
||||
},
|
||||
"tunnel": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
|
||||
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="
|
||||
},
|
||||
"util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
||||
},
|
||||
"uuid": {
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
|
||||
},
|
||||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.9.1",
|
||||
"@vercel/ncc": "^0.34.0",
|
||||
"tar-stream": "^2.2.0"
|
||||
}
|
||||
}
|
||||
@@ -7,9 +7,13 @@ on:
|
||||
- "release/*"
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
run-lr-tests:
|
||||
description: 'Run long running tests'
|
||||
type: boolean
|
||||
|
||||
permissions:
|
||||
packages: read
|
||||
packages: write
|
||||
contents: read
|
||||
|
||||
defaults:
|
||||
@@ -40,9 +44,6 @@ jobs:
|
||||
matrix:
|
||||
platform: ${{fromJSON(needs.d.outputs.missing-platforms)}}
|
||||
runs-on: ["self-hosted", "enf-x86-beefy"]
|
||||
permissions:
|
||||
packages: write
|
||||
contents: read
|
||||
steps:
|
||||
- name: Login to Container Registry
|
||||
uses: docker/login-action@v2
|
||||
@@ -56,7 +57,6 @@ jobs:
|
||||
push: true
|
||||
tags: ${{fromJSON(needs.d.outputs.p)[matrix.platform].image}}
|
||||
file: ${{fromJSON(needs.d.outputs.p)[matrix.platform].dockerfile}}
|
||||
|
||||
Build:
|
||||
needs: [d, build-platforms]
|
||||
if: always() && needs.d.result == 'success' && (needs.build-platforms.result == 'success' || needs.build-platforms.result == 'skipped')
|
||||
@@ -64,6 +64,8 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [ubuntu18, ubuntu20, ubuntu22]
|
||||
outputs:
|
||||
lr-tests: ${{steps.build.outputs.lr-tests}}
|
||||
runs-on: ["self-hosted", "enf-x86-beefy"]
|
||||
container: ${{fromJSON(needs.d.outputs.p)[matrix.platform].image}}
|
||||
steps:
|
||||
@@ -79,38 +81,25 @@ jobs:
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr -GNinja ..
|
||||
ninja
|
||||
tar -pc -C .. --exclude "*.o" build | zstd --long -T0 -9 > ../build.tar.zst
|
||||
# the correct approach is by far "--show-only=json-v1 | jq '.tests[].name' | jq -sc" but that doesn't work on U18's cmake 3.10 since it lacks json-v1
|
||||
echo ::set-output name=lr-tests::$(ctest -L "long_running_tests" --show-only | head -n -1 | cut -d ':' -f 2 -s | jq -cnR '[inputs | select(length>0)[1:]]')
|
||||
tar -pc -C .. --exclude "*.a" --exclude "*.o" build | zstd --long -T0 -9 > ../build.tar.gz
|
||||
- name: Upload builddir
|
||||
uses: AntelopeIO/upload-artifact-large-chunks-action@v1
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{matrix.platform}}-build
|
||||
path: build.tar.zst
|
||||
|
||||
dev-package:
|
||||
name: Build leap-dev package
|
||||
needs: [d, Build]
|
||||
if: always() && needs.Build.result == 'success'
|
||||
runs-on: ubuntu-latest
|
||||
container: ${{fromJSON(needs.d.outputs.p)['ubuntu20'].image}}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
- name: Download builddir
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: ubuntu20-build
|
||||
- name: Build dev package
|
||||
run: |
|
||||
zstdcat build.tar.zst | tar x
|
||||
cd build
|
||||
cpack
|
||||
- name: Upload dev package
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: leap-dev-ubuntu20-amd64
|
||||
path: build/leap-dev*.deb
|
||||
|
||||
path: build.tar.gz
|
||||
- name: Build dev package (Ubuntu 20 only)
|
||||
if: matrix.platform == 'ubuntu20'
|
||||
run: |
|
||||
cd build
|
||||
ninja package
|
||||
- name: Upload dev package (Ubuntu 20 only)
|
||||
if: matrix.platform == 'ubuntu20'
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: leap-dev-ubuntu20-amd64
|
||||
path: build/leap-dev*.deb
|
||||
tests:
|
||||
name: Tests
|
||||
needs: [d, Build]
|
||||
@@ -118,11 +107,13 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [ubuntu20, ubuntu22]
|
||||
runs-on: ["self-hosted", "enf-x86-hightier"]
|
||||
platform: [ubuntu20]
|
||||
runs-on: ["self-hosted", "enf-x86-beefy"]
|
||||
container: ${{fromJSON(needs.d.outputs.p)[matrix.platform].image}}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
- name: Download builddir
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
@@ -131,13 +122,9 @@ jobs:
|
||||
run: |
|
||||
# https://github.com/actions/runner/issues/2033 -- need this because of full version label test looking at git revs
|
||||
chown -R $(id -u):$(id -g) $PWD
|
||||
# jammy's boost 1.74 can stumble on an EXDEV via copy_file_range() it doesn't have a fallback for; re-eval once moving to std::filesystem
|
||||
export TMPDIR="$PWD/tmp"
|
||||
mkdir -p $TMPDIR
|
||||
zstdcat build.tar.zst | tar x
|
||||
zstdcat build.tar.gz | tar x
|
||||
cd build
|
||||
ctest --output-on-failure -j $(nproc) -LE "(nonparallelizable_tests|long_running_tests)"
|
||||
|
||||
np-tests:
|
||||
name: NP Tests
|
||||
needs: [d, Build]
|
||||
@@ -145,62 +132,70 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [ubuntu18, ubuntu20, ubuntu22]
|
||||
runs-on: ["self-hosted", "enf-x86-midtier"]
|
||||
platform: [ubuntu20]
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ${{fromJSON(needs.d.outputs.p)[matrix.platform].image}}
|
||||
options: --init
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Download builddir
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: ${{matrix.platform}}-build
|
||||
- name: Run tests in parallel containers
|
||||
uses: ./.github/actions/parallel-ctest-containers
|
||||
with:
|
||||
container: ${{fromJSON(needs.d.outputs.p)[matrix.platform].image}}
|
||||
error-log-paths: '["build/etc", "build/var", "build/leap-ignition-wd"]'
|
||||
log-tarball-prefix: ${{matrix.platform}}
|
||||
tests-label: nonparallelizable_tests
|
||||
- name: Run NP Tests
|
||||
run: |
|
||||
zstdcat build.tar.gz | tar x
|
||||
cd build
|
||||
ctest --output-on-failure -L "nonparallelizable_tests"
|
||||
- name: Bundle logs from failed tests
|
||||
if: failure()
|
||||
run: tar --ignore-failed-read -czf ${{matrix.platform}}-serial-logs.tar.gz build/var build/etc build/leap-ignition-wd
|
||||
- name: Upload logs from failed tests
|
||||
uses: actions/upload-artifact@v3
|
||||
if: failure()
|
||||
with:
|
||||
name: ${{matrix.platform}}-np-logs
|
||||
path: '*-logs.tar.gz'
|
||||
|
||||
name: ${{matrix.platform}}-serial-logs
|
||||
path: ${{matrix.platform}}-serial-logs.tar.gz
|
||||
lr-tests:
|
||||
name: LR Tests
|
||||
needs: [d, Build]
|
||||
if: always() && needs.Build.result == 'success'
|
||||
if: always() && needs.Build.result == 'success' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/') || inputs.run-lr-tests)
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [ubuntu18, ubuntu20, ubuntu22]
|
||||
runs-on: ["self-hosted", "enf-x86-lowtier"]
|
||||
platform: [ubuntu20]
|
||||
test-name: ${{fromJSON(needs.Build.outputs.lr-tests)}}
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ${{fromJSON(needs.d.outputs.p)[matrix.platform].image}}
|
||||
options: --init
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Download builddir
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: ${{matrix.platform}}-build
|
||||
- name: Run tests in parallel containers
|
||||
uses: ./.github/actions/parallel-ctest-containers
|
||||
with:
|
||||
container: ${{fromJSON(needs.d.outputs.p)[matrix.platform].image}}
|
||||
error-log-paths: '["build/etc", "build/var", "build/leap-ignition-wd"]'
|
||||
log-tarball-prefix: ${{matrix.platform}}
|
||||
tests-label: long_running_tests
|
||||
- name: Upload logs from failed tests
|
||||
- name: Run ${{matrix.test-name}} Test
|
||||
run: |
|
||||
zstdcat build.tar.gz | tar x
|
||||
cd build
|
||||
ctest --output-on-failure -R ${{matrix.test-name}}
|
||||
- name: Bundle logs from failed tests
|
||||
if: failure()
|
||||
run: tar --ignore-failed-read -czf ${{matrix.platform}}-${{matrix.test-name}}-logs.tar.gz build/var build/etc build/leap-ignition-wd
|
||||
- name: Upload logs from failed tests
|
||||
uses: actions/upload-artifact@v3
|
||||
if: failure()
|
||||
with:
|
||||
name: ${{matrix.platform}}-lr-logs
|
||||
path: '*-logs.tar.gz'
|
||||
name: ${{matrix.platform}}-${{matrix.test-name}}-logs
|
||||
path: ${{matrix.platform}}-${{matrix.test-name}}-logs.tar.gz
|
||||
|
||||
all-passing:
|
||||
name: All Required Tests Passed
|
||||
needs: [dev-package, tests, np-tests]
|
||||
needs: [tests, np-tests]
|
||||
if: always()
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- if: needs.dev-package.result != 'success' || needs.tests.result != 'success' || needs.np-tests.result != 'success'
|
||||
- if: needs.tests.result != 'success' || needs.np-tests.result != 'success'
|
||||
run: false
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
name: Jira Issue Creator
|
||||
on:
|
||||
issues:
|
||||
types:
|
||||
- labeled
|
||||
|
||||
jobs:
|
||||
create-jira-issue:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.label.name == 'OCI'
|
||||
steps:
|
||||
- name: Create json issue file
|
||||
run: |
|
||||
cat << EOF > issue.json
|
||||
{
|
||||
"fields": {
|
||||
"project":
|
||||
{
|
||||
"key": "$JIRA_PROJECT_KEY"
|
||||
},
|
||||
"summary": "$JIRA_ISSUE_SUMMARY",
|
||||
"description": "$JIRA_ISSUE_DESCRIPTION",
|
||||
"issuetype": {
|
||||
"name": "$JIRA_ISSUE_TYPE_NAME"
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
env:
|
||||
JIRA_PROJECT_KEY: ${{ secrets.JIRA_PROJECT_KEY }}
|
||||
JIRA_ISSUE_SUMMARY: ${{ github.event.issue.title }}
|
||||
JIRA_ISSUE_DESCRIPTION: "${{ github.event.issue.url }}\\n\\n${{ github.event.issue.html_url }}"
|
||||
JIRA_ISSUE_TYPE_NAME: "Story"
|
||||
- name: Check issue json
|
||||
run: |
|
||||
cat issue.json
|
||||
- name: Trigger jira issue creation
|
||||
run: |
|
||||
curl -u $JIRA_AUTH -X POST --data @issue.json -H "Content-Type: application/json" --url $JIRA_PROJECT_URL
|
||||
env:
|
||||
JIRA_AUTH: ${{ secrets.JIRA_USN_AND_TOKEN }}
|
||||
JIRA_PROJECT_URL: ${{ secrets.JIRA_PROJECT_URL }}
|
||||
@@ -1,17 +0,0 @@
|
||||
name: Label New Issue
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: opened
|
||||
|
||||
jobs:
|
||||
label_new_issue:
|
||||
uses: AntelopeIO/issue-project-labeler-workflow/.github/workflows/issue-project-labeler.yaml@v1
|
||||
with:
|
||||
issue-id: ${{github.event.issue.node_id}}
|
||||
label: triage
|
||||
org-project: 'Team Backlog'
|
||||
project-field: Status=Todo
|
||||
secrets:
|
||||
token: ${{secrets.ENFCIBOT_REPO_AND_PROJECTS}}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
name: "Pinned Build"
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
packages: read
|
||||
contents: read
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
Build:
|
||||
name: Build
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [ubuntu18, ubuntu20, ubuntu22]
|
||||
runs-on: ["self-hosted", "enf-x86-beefy-long"]
|
||||
container: ${{ matrix.platform == 'ubuntu18' && 'ubuntu:bionic' || matrix.platform == 'ubuntu20' && 'ubuntu:focal' || 'ubuntu:jammy' }}
|
||||
steps:
|
||||
- name: Conditionally update git repo
|
||||
if: ${{ matrix.platform == 'ubuntu18' }}
|
||||
run: |
|
||||
apt-get update
|
||||
apt-get install -y software-properties-common
|
||||
apt-get update
|
||||
add-apt-repository ppa:git-core/ppa
|
||||
- name: Update and Install git
|
||||
run: |
|
||||
apt-get update
|
||||
apt-get install -y git
|
||||
git --version
|
||||
- name: Clone leap
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
# https://github.com/actions/runner/issues/2033
|
||||
chown -R $(id -u):$(id -g) $PWD
|
||||
./scripts/install_deps.sh
|
||||
- name: Build Pinned Build
|
||||
env:
|
||||
LEAP_PINNED_INSTALL_PREFIX: /usr
|
||||
run: |
|
||||
./scripts/pinned_build.sh deps build "$(nproc)"
|
||||
- name: Upload package
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: leap-${{matrix.platform}}-pinned-amd64
|
||||
path: build/leap-3*.deb
|
||||
- name: Run Parallel Tests
|
||||
run: |
|
||||
cd build
|
||||
ctest --output-on-failure -j $(nproc) -LE "(nonparallelizable_tests|long_running_tests)" --timeout 420
|
||||
@@ -10,7 +10,6 @@
|
||||
*.abi.hpp
|
||||
*.cmake
|
||||
!.cicd
|
||||
!package.cmake
|
||||
!CMakeModules/*.cmake
|
||||
*.ninja
|
||||
\#*
|
||||
|
||||
+6
-12
@@ -7,24 +7,18 @@
|
||||
[submodule "libraries/eos-vm"]
|
||||
path = libraries/eos-vm
|
||||
url = https://github.com/AntelopeIO/eos-vm
|
||||
[submodule "libraries/fc"]
|
||||
path = libraries/fc
|
||||
url = https://github.com/AntelopeIO/fc
|
||||
[submodule "libraries/softfloat"]
|
||||
path = libraries/softfloat
|
||||
url = https://github.com/AntelopeIO/berkeley-softfloat-3
|
||||
[submodule "libraries/rapidjson"]
|
||||
path = libraries/rapidjson
|
||||
url = https://github.com/Tencent/rapidjson/
|
||||
[submodule "libraries/yubihsm"]
|
||||
path = libraries/yubihsm
|
||||
url = https://github.com/Yubico/yubihsm-shell
|
||||
[submodule "tests/abieos"]
|
||||
path = tests/abieos
|
||||
url = https://github.com/AntelopeIO/abieos
|
||||
[submodule "libraries/libfc/include/fc/crypto/webauthn_json"]
|
||||
path = libraries/libfc/include/fc/crypto/webauthn_json
|
||||
url = https://github.com/Tencent/rapidjson/
|
||||
[submodule "libraries/libfc/secp256k1/secp256k1"]
|
||||
path = libraries/libfc/secp256k1/secp256k1
|
||||
url = https://github.com/bitcoin-core/secp256k1
|
||||
[submodule "libraries/libfc/libraries/ff"]
|
||||
path = libraries/libfc/libraries/ff
|
||||
url = https://github.com/AntelopeIO/libff
|
||||
[submodule "wasm-spec-tests"]
|
||||
path = wasm-spec-tests
|
||||
url = https://github.com/AntelopeIO/wasm-spec-tests
|
||||
|
||||
+36
-29
@@ -14,9 +14,9 @@ set( CMAKE_CXX_EXTENSIONS ON )
|
||||
set( CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
set(VERSION_MAJOR 3)
|
||||
set(VERSION_MINOR 2)
|
||||
set(VERSION_PATCH 0)
|
||||
#set(VERSION_SUFFIX rc2)
|
||||
set(VERSION_MINOR 1)
|
||||
set(VERSION_PATCH 5)
|
||||
#set(VERSION_SUFFIX rc4)
|
||||
|
||||
if(VERSION_SUFFIX)
|
||||
set(VERSION_FULL "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}-${VERSION_SUFFIX}")
|
||||
@@ -27,7 +27,6 @@ endif()
|
||||
set( CLI_CLIENT_EXECUTABLE_NAME cleos )
|
||||
set( NODE_EXECUTABLE_NAME nodeos )
|
||||
set( KEY_STORE_EXECUTABLE_NAME keosd )
|
||||
set( LEAP_UTIL_EXECUTABLE_NAME leap-util )
|
||||
|
||||
# http://stackoverflow.com/a/18369825
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
@@ -54,11 +53,7 @@ set(ENABLE_MULTIVERSION_PROTOCOL_TEST FALSE CACHE BOOL "Enable nodeos multiversi
|
||||
|
||||
# add defaults for openssl
|
||||
if(APPLE AND UNIX AND "${OPENSSL_ROOT_DIR}" STREQUAL "")
|
||||
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64")
|
||||
set(OPENSSL_ROOT_DIR "/opt/homebrew/opt/openssl@3;/opt/homebrew/opt/openssl@1.1")
|
||||
else()
|
||||
set(OPENSSL_ROOT_DIR "/usr/local/opt/openssl@3;/usr/local/opt/openssl@1.1")
|
||||
endif()
|
||||
set(OPENSSL_ROOT_DIR "/usr/local/opt/openssl@3;/usr/local/opt/openssl@1.1")
|
||||
endif()
|
||||
# fc also adds these definitions to its public interface. once fc becomes the sole importer of openssl, this should be removed
|
||||
add_definitions(-DOPENSSL_API_COMPAT=0x10100000L -DOPENSSL_NO_DEPRECATED)
|
||||
@@ -182,10 +177,13 @@ add_subdirectory( scripts )
|
||||
add_subdirectory( unittests )
|
||||
add_subdirectory( tests )
|
||||
add_subdirectory( tools )
|
||||
add_subdirectory( benchmark )
|
||||
|
||||
option(DISABLE_WASM_SPEC_TESTS "disable building of wasm spec unit tests" OFF)
|
||||
|
||||
if (NOT DISABLE_WASM_SPEC_TESTS)
|
||||
add_subdirectory( wasm-spec-tests/generated-tests )
|
||||
endif()
|
||||
|
||||
install(FILES testnet.template DESTINATION ${CMAKE_INSTALL_FULL_SYSCONFDIR}/eosio/launcher COMPONENT dev EXCLUDE_FROM_ALL)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/testnet.template ${CMAKE_CURRENT_BINARY_DIR}/etc/eosio/launcher/testnet.template COPYONLY)
|
||||
|
||||
@@ -215,26 +213,35 @@ install(FILES ${CMAKE_BINARY_DIR}/modules/leap-config.cmake DESTINATION ${CMAKE_
|
||||
install(FILES ${CMAKE_BINARY_DIR}/modules/EosioTester.cmake DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}/cmake/leap COMPONENT dev EXCLUDE_FROM_ALL)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/CMakeModules/EosioCheckVersion.cmake DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}/cmake/leap COMPONENT dev EXCLUDE_FROM_ALL)
|
||||
|
||||
configure_file(LICENSE licenses/leap/LICENSE COPYONLY)
|
||||
configure_file(libraries/softfloat/COPYING.txt licenses/leap/LICENSE.softfloat COPYONLY)
|
||||
configure_file(libraries/wasm-jit/LICENSE licenses/leap/LICENSE.wavm COPYONLY)
|
||||
configure_file(libraries/libfc/secp256k1/secp256k1/COPYING licenses/leap/LICENSE.secp256k1 COPYONLY)
|
||||
configure_file(libraries/libfc/include/fc/crypto/webauthn_json/license.txt licenses/leap/LICENSE.rapidjson COPYONLY)
|
||||
configure_file(libraries/libfc/src/network/LICENSE.go licenses/leap/LICENSE.go COPYONLY)
|
||||
configure_file(libraries/eos-vm/LICENSE licenses/leap/LICENSE.eos-vm COPYONLY)
|
||||
configure_file(libraries/libfc/libraries/ff/LICENSE licenses/leap/LICENSE.libff COPYONLY)
|
||||
configure_file(programs/cleos/LICENSE.CLI11 licenses/leap/LICENSE.CLI11 COPYONLY)
|
||||
configure_file(libraries/yubihsm/LICENSE licenses/leap/LICENSE.yubihsm COPYONLY)
|
||||
configure_file(${CMAKE_SOURCE_DIR}/LICENSE
|
||||
${CMAKE_BINARY_DIR}/licenses/leap/LICENSE COPYONLY)
|
||||
configure_file(${CMAKE_SOURCE_DIR}/libraries/softfloat/COPYING.txt
|
||||
${CMAKE_BINARY_DIR}/licenses/leap/LICENSE.softfloat COPYONLY)
|
||||
configure_file(${CMAKE_SOURCE_DIR}/libraries/wasm-jit/LICENSE
|
||||
${CMAKE_BINARY_DIR}/licenses/leap/LICENSE.wavm COPYONLY)
|
||||
configure_file(${CMAKE_SOURCE_DIR}/libraries/fc/secp256k1/secp256k1/COPYING
|
||||
${CMAKE_BINARY_DIR}/licenses/leap/LICENSE.secp256k1 COPYONLY)
|
||||
configure_file(${CMAKE_SOURCE_DIR}/libraries/fc/include/fc/crypto/webauthn_json/license.txt
|
||||
${CMAKE_BINARY_DIR}/licenses/leap/LICENSE.rapidjson COPYONLY)
|
||||
configure_file(${CMAKE_SOURCE_DIR}/libraries/fc/src/network/LICENSE.go
|
||||
${CMAKE_BINARY_DIR}/licenses/leap/LICENSE.go COPYONLY)
|
||||
configure_file(${CMAKE_SOURCE_DIR}/libraries/yubihsm/LICENSE
|
||||
${CMAKE_BINARY_DIR}/licenses/leap/LICENSE.yubihsm COPYONLY)
|
||||
configure_file(${CMAKE_SOURCE_DIR}/libraries/eos-vm/LICENSE
|
||||
${CMAKE_BINARY_DIR}/licenses/leap/LICENSE.eos-vm COPYONLY)
|
||||
configure_file(${CMAKE_SOURCE_DIR}/programs/cleos/LICENSE.CLI11
|
||||
${CMAKE_BINARY_DIR}/programs/cleos/LICENSE.CLI11 COPYONLY)
|
||||
|
||||
install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/licenses/leap" DESTINATION "${CMAKE_INSTALL_FULL_DATAROOTDIR}/licenses/" COMPONENT base)
|
||||
|
||||
configure_file(${CMAKE_SOURCE_DIR}/libraries/cli11/bash-completion/completions/leap-util
|
||||
${CMAKE_BINARY_DIR}/programs/leap-util/bash-completion/completions/leap-util COPYONLY)
|
||||
configure_file(${CMAKE_SOURCE_DIR}/libraries/cli11/bash-completion/completions/cleos
|
||||
${CMAKE_BINARY_DIR}/programs/cleos/bash-completion/completions/cleos COPYONLY)
|
||||
|
||||
install(FILES libraries/cli11/bash-completion/completions/leap-util DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/bash-completion/completions COMPONENT base)
|
||||
install(FILES libraries/cli11/bash-completion/completions/cleos DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/bash-completion/completions COMPONENT base)
|
||||
install(FILES LICENSE DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/licenses/leap/ COMPONENT base)
|
||||
install(FILES libraries/softfloat/COPYING.txt DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/licenses/leap/ RENAME LICENSE.softfloat COMPONENT base)
|
||||
install(FILES libraries/wasm-jit/LICENSE DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/licenses/leap/ RENAME LICENSE.wavm COMPONENT base)
|
||||
install(FILES libraries/fc/secp256k1/secp256k1/COPYING DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/licenses/leap/ RENAME LICENSE.secp256k1 COMPONENT base)
|
||||
install(FILES libraries/fc/include/fc/crypto/webauthn_json/license.txt DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/licenses/leap/ RENAME LICENSE.rapidjson COMPONENT base)
|
||||
install(FILES libraries/fc/src/network/LICENSE.go DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/licenses/leap/ COMPONENT base)
|
||||
install(FILES libraries/yubihsm/LICENSE DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/licenses/leap/ RENAME LICENSE.yubihsm COMPONENT base)
|
||||
install(FILES libraries/eos-vm/LICENSE DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/licenses/leap/ RENAME LICENSE.eos-vm COMPONENT base)
|
||||
install(FILES libraries/fc/libraries/ff/LICENSE DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/licenses/leap/ RENAME LICENSE.libff COMPONENT base)
|
||||
install(FILES programs/cleos/LICENSE.CLI11 DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/licenses/leap/ COMPONENT base)
|
||||
|
||||
add_custom_target(dev-install
|
||||
COMMAND "${CMAKE_COMMAND}" --build "${CMAKE_BINARY_DIR}"
|
||||
|
||||
@@ -54,8 +54,13 @@ find_package(Boost @Boost_MAJOR_VERSION@.@Boost_MINOR_VERSION@ EXACT REQUIRED CO
|
||||
|
||||
find_library(libtester eosio_testing @CMAKE_INSTALL_FULL_LIBDIR@ NO_DEFAULT_PATH)
|
||||
find_library(libchain eosio_chain @CMAKE_INSTALL_FULL_LIBDIR@ NO_DEFAULT_PATH)
|
||||
find_library(libfc fc @CMAKE_INSTALL_FULL_LIBDIR@ NO_DEFAULT_PATH)
|
||||
find_library(libsecp256k1 secp256k1 @CMAKE_INSTALL_FULL_LIBDIR@ NO_DEFAULT_PATH)
|
||||
if ( "${CMAKE_BUILD_TYPE}" STREQUAL "Debug" )
|
||||
find_library(libfc fc_debug @CMAKE_INSTALL_FULL_LIBDIR@ NO_DEFAULT_PATH)
|
||||
find_library(libsecp256k1 secp256k1_debug @CMAKE_INSTALL_FULL_LIBDIR@ NO_DEFAULT_PATH)
|
||||
else()
|
||||
find_library(libfc fc @CMAKE_INSTALL_FULL_LIBDIR@ NO_DEFAULT_PATH)
|
||||
find_library(libsecp256k1 secp256k1 @CMAKE_INSTALL_FULL_LIBDIR@ NO_DEFAULT_PATH)
|
||||
endif()
|
||||
|
||||
find_library(libff ff @CMAKE_INSTALL_FULL_LIBDIR@ NO_DEFAULT_PATH)
|
||||
find_library(libwasm WASM @CMAKE_INSTALL_FULL_LIBDIR@ NO_DEFAULT_PATH)
|
||||
|
||||
@@ -51,10 +51,16 @@ find_package(Boost @Boost_MAJOR_VERSION@.@Boost_MINOR_VERSION@ EXACT REQUIRED CO
|
||||
|
||||
find_library(libtester eosio_testing @CMAKE_BINARY_DIR@/libraries/testing NO_DEFAULT_PATH)
|
||||
find_library(libchain eosio_chain @CMAKE_BINARY_DIR@/libraries/chain NO_DEFAULT_PATH)
|
||||
find_library(libfc fc @CMAKE_BINARY_DIR@/libraries/libfc NO_DEFAULT_PATH)
|
||||
find_library(libsecp256k1 secp256k1 @CMAKE_BINARY_DIR@/libraries/libfc/secp256k1 NO_DEFAULT_PATH)
|
||||
if ( "${CMAKE_BUILD_TYPE}" STREQUAL "Debug" )
|
||||
find_library(libfc fc_debug @CMAKE_BINARY_DIR@/libraries/fc NO_DEFAULT_PATH)
|
||||
find_library(libsecp256k1 secp256k1_debug @CMAKE_BINARY_DIR@/libraries/fc/secp256k1 NO_DEFAULT_PATH)
|
||||
|
||||
find_library(libff ff @CMAKE_BINARY_DIR@/libraries/libfc/libraries/ff/libff NO_DEFAULT_PATH)
|
||||
else()
|
||||
find_library(libfc fc @CMAKE_BINARY_DIR@/libraries/fc NO_DEFAULT_PATH)
|
||||
find_library(libsecp256k1 secp256k1 @CMAKE_BINARY_DIR@/libraries/fc/secp256k1 NO_DEFAULT_PATH)
|
||||
endif()
|
||||
|
||||
find_library(libff ff @CMAKE_BINARY_DIR@/libraries/fc/libraries/ff/libff NO_DEFAULT_PATH)
|
||||
find_library(libwasm WASM @CMAKE_BINARY_DIR@/libraries/wasm-jit/Source/WASM NO_DEFAULT_PATH)
|
||||
find_library(libwast WAST @CMAKE_BINARY_DIR@/libraries/wasm-jit/Source/WAST NO_DEFAULT_PATH)
|
||||
find_library(libir IR @CMAKE_BINARY_DIR@/libraries/wasm-jit/Source/IR NO_DEFAULT_PATH)
|
||||
@@ -123,7 +129,7 @@ macro(add_eosio_test_executable test_name)
|
||||
@OPENSSL_INCLUDE_DIR@
|
||||
@CMAKE_SOURCE_DIR@/libraries/chain/include
|
||||
@CMAKE_BINARY_DIR@/libraries/chain/include
|
||||
@CMAKE_SOURCE_DIR@/libraries/libfc/include
|
||||
@CMAKE_SOURCE_DIR@/libraries/fc/include
|
||||
@CMAKE_SOURCE_DIR@/libraries/softfloat/source/include
|
||||
@CMAKE_SOURCE_DIR@/libraries/appbase/include
|
||||
@CMAKE_SOURCE_DIR@/libraries/chainbase/include
|
||||
@@ -170,7 +176,7 @@ if(ENABLE_COVERAGE_TESTING)
|
||||
|
||||
COMMAND ${LCOV_PATH} --directory . --capture --gcov-tool ${CMAKE_SOURCE_DIR}/tools/llvm-gcov.sh --output-file ${Coverage_NAME}.info
|
||||
|
||||
COMMAND ${LCOV_PATH} -remove ${Coverage_NAME}.info '*/boost/*' '/usr/lib/*' '/usr/include/*' '*/externals/*' '*/libfc/*' '*/wasm-jit/*' --output-file ${Coverage_NAME}_filtered.info
|
||||
COMMAND ${LCOV_PATH} -remove ${Coverage_NAME}.info '*/boost/*' '/usr/lib/*' '/usr/include/*' '*/externals/*' '*/fc/*' '*/wasm-jit/*' --output-file ${Coverage_NAME}_filtered.info
|
||||
|
||||
COMMAND ${GENHTML_PATH} -o ${Coverage_NAME} ${PROJECT_BINARY_DIR}/${Coverage_NAME}_filtered.info
|
||||
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
file(GLOB BENCHMARK "*.cpp")
|
||||
add_executable( benchmark ${BENCHMARK} )
|
||||
|
||||
target_link_libraries( benchmark fc Boost::program_options )
|
||||
target_include_directories( benchmark PUBLIC
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
)
|
||||
@@ -1,123 +0,0 @@
|
||||
#include <iostream>
|
||||
|
||||
#include <fc/crypto/alt_bn128.hpp>
|
||||
|
||||
#include <benchmark.hpp>
|
||||
|
||||
namespace benchmark {
|
||||
|
||||
using bytes = std::vector<char>;
|
||||
using g1g2_pair = std::vector<std::string>;
|
||||
|
||||
void add_benchmarking() {
|
||||
std::vector<unsigned char> point1_raw = {
|
||||
12,175,215,144,98,95,151,228,179,85,31,170,172,159,40,255,250,252,68,28,235,65,172,180,69,164,153,29,187,239,220,201, // x
|
||||
18,102,219,76,79,148,120,28,39,149,42,172,41,248,120,249,255,69,42,51,160,239,13,219,239,183,77,174,217,158,130,10,}; // y
|
||||
std::vector<unsigned char> point2_raw = {
|
||||
12,144,10,32,104,85,103,36,222,232,48,152,108,217,40,145,230,48,8,54,0,7,134,164,7,10,139,110,95,205,124,121, // x
|
||||
22,254,176,251,18,168,78,220,142,100,102,113,58,176,83,186,212,62,154,138,235,135,34,46,237,117,54,36,198,40,79,73,}; // y
|
||||
|
||||
bytes point1, point2;
|
||||
point1.insert(point1.begin(), point1_raw.begin(), point1_raw.end());
|
||||
point2.insert(point2.begin(), point2_raw.begin(), point2_raw.end());
|
||||
|
||||
auto f = [&]() {
|
||||
auto res = fc::alt_bn128_add(point1, point2);
|
||||
if (std::holds_alternative<fc::alt_bn128_error>(res)) {
|
||||
std::cout << "alt_bn128_add failed: "
|
||||
<< (int)std::get<fc::alt_bn128_error>(res) << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
benchmarking("alt_bn128_add", f);
|
||||
}
|
||||
|
||||
void mul_benchmarking() {
|
||||
std::vector<unsigned char> point_raw = {
|
||||
12,175,215,144,98,95,151,228,179,85,31,170,172,159,40,255,250,252,68,28,235,65,172,180,69,164,153,29,187,239,220,201, // x
|
||||
18,102,219,76,79,148,120,28,39,149,42,172,41,248,120,249,255,69,42,51,160,239,13,219,239,183,77,174,217,158,130,10,}; // y
|
||||
std::vector<unsigned char> scaler_raw = {
|
||||
25,62,182,170,104,140,135,90,37,150,0,77,2,77,146,71,54,101,113,69,177,216,157,4,229,213,33,215,169,99,150,91, }; // scaler size 256 bits
|
||||
|
||||
bytes point, scaler;
|
||||
point.insert(point.begin(), point_raw.begin(), point_raw.end());
|
||||
scaler.insert(scaler.begin(), scaler_raw.begin(), scaler_raw.end());
|
||||
|
||||
auto f = [&]() {
|
||||
auto res = fc::alt_bn128_mul(point, scaler);
|
||||
if (std::holds_alternative<fc::alt_bn128_error>(res)) {
|
||||
std::cout << "alt_bn128_mul failed: "
|
||||
<< (int)std::get<fc::alt_bn128_error>(res) << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
benchmarking("alt_bn128_mul", f);
|
||||
}
|
||||
|
||||
void pair_benchmarking() {
|
||||
std::vector<unsigned char> g1_g2_pairs_raw = {
|
||||
/* pair 1 */
|
||||
12,175,215,144,98,95,151,228,179,85,31,170,172,159,40,255,250,252,68,28,235,65,172,180,69,164,153,29,187,239,220,201,18,102,219,76,79,148,120,28,39,149,42,172,41,248,120,249,255,69,42,51,160,239,13,219,239,183,77,174,217,158,130,10,
|
||||
46,24,234,176,148,82,198,136,44,30,157,18,217,25,49,241,63,197,2,151,14,150,136,210,114,4,74,124,145,225,131,139,13,60,0,50,236,103,39,15,150,226,246,189,209,113,0,46,151,39,41,6,87,119,228,213,45,225,29,234,161,110,43,87,3,237,74,227,93,23,171,129,49,118,228,173,154,111,168,220,161,46,140,103,155,56,168,207,254,90,228,76,188,232,25,34,44,102,159,35,193,216,177,31,131,247,226,19,170,222,26,227,86,37,81,149,202,144,188,126,120,168,9,195,32,169,147,161,
|
||||
/* pair,2,*/
|
||||
12,144,10,32,104,85,103,36,222,232,48,152,108,217,40,145,230,48,8,54,0,7,134,164,7,10,139,110,95,205,124,121,22,254,176,251,18,168,78,220,142,100,102,113,58,176,83,186,212,62,154,138,235,135,34,46,237,117,54,36,198,40,79,73,
|
||||
0,186,148,242,227,252,208,242,165,128,1,160,59,2,6,195,30,54,69,118,8,28,223,92,254,98,110,219,90,92,7,113,26,8,119,98,122,61,119,91,216,107,29,179,122,218,203,6,84,109,119,140,44,12,57,157,203,90,14,108,218,54,94,44,42,77,118,169,232,192,189,60,129,213,156,157,215,160,91,214,138,130,119,145,167,89,237,149,225,85,151,33,89,181,224,235,2,91,213,225,37,226,214,14,255,84,254,117,142,211,28,164,78,254,64,11,126,217,25,124,203,220,52,181,39,32,78,132,
|
||||
/* pair 3 */
|
||||
48,58,116,183,56,3,62,111,104,127,0,7,202,204,146,2,236,192,214,213,231,100,12,17,104,47,76,49,149,39,35,179,2,162,218,104,52,130,61,134,223,111,123,225,186,122,171,2,144,236,110,29,26,142,113,183,238,44,130,30,76,212,52,15,
|
||||
19,206,16,79,220,158,153,194,12,48,10,79,173,10,97,199,113,25,255,87,220,3,102,235,164,170,50,240,177,237,223,205,11,75,211,28,143,229,192,35,171,167,172,238,138,235,82,134,111,165,144,29,118,150,179,21,158,9,202,2,242,109,33,148,14,188,33,145,213,186,0,126,178,10,131,168,121,66,121,193,106,209,176,34,176,41,145,227,3,55,245,150,82,218,232,155,31,153,213,183,157,2,159,247,25,69,49,215,219,36,46,5,192,205,201,182,72,189,84,62,61,47,136,81,51,65,231,161,
|
||||
/* pair 4 */
|
||||
27,31,150,92,17,82,135,210,46,161,0,24,16,199,200,165,29,165,157,168,222,9,83,17,44,27,64,226,208,112,223,128,20,253,182,130,45,130,249,9,168,206,153,86,197,214,59,248,241,191,93,113,70,113,247,244,43,214,240,246,24,38,33,50,
|
||||
23,76,241,195,191,99,69,237,123,173,212,42,74,85,138,108,39,80,105,135,226,11,84,237,39,73,180,224,42,230,246,76,26,61,86,57,253,213,223,2,93,42,38,186,38,38,206,38,209,138,153,181,57,89,16,187,234,2,110,23,12,14,252,240,32,231,237,147,16,62,220,6,160,64,154,167,57,238,243,112,255,35,80,36,100,173,21,58,96,244,77,245,75,202,24,63,35,178,46,215,219,69,120,221,70,119,111,195,145,45,109,84,206,76,254,205,98,167,30,72,117,5,128,129,156,128,196,192,
|
||||
/* pair 5 */
|
||||
33,230,106,254,43,77,114,126,9,205,25,63,9,170,62,237,149,102,198,184,60,31,185,213,103,120,71,249,28,106,238,107,1,133,60,180,58,152,18,177,142,248,46,186,90,34,94,200,235,158,242,255,209,32,143,133,102,195,19,107,153,42,207,228,
|
||||
30,43,165,137,133,231,242,156,65,126,94,159,26,27,78,164,165,159,225,150,220,158,247,118,118,170,195,122,12,125,8,34,39,57,159,231,167,233,3,47,243,142,174,224,162,38,147,65,74,191,98,144,126,125,81,177,75,140,161,27,34,97,46,249,8,65,220,15,139,144,78,12,72,239,54,163,39,6,30,147,154,208,89,111,170,126,6,214,32,181,195,140,215,53,218,239,44,43,229,0,169,242,16,227,163,185,224,21,142,203,135,66,60,53,91,80,48,112,8,13,226,206,58,249,163,52,196,53,
|
||||
/* pair 6 */
|
||||
14,157,100,136,255,206,130,101,56,187,235,39,67,209,67,124,40,174,153,135,155,26,166,170,118,193,244,21,70,71,120,150,3,189,254,120,183,98,23,175,175,28,195,233,165,224,35,95,247,132,40,64,26,208,70,206,247,92,134,105,118,181,21,242,
|
||||
16,159,200,208,93,99,234,139,8,222,239,67,3,187,15,125,5,144,190,196,146,171,15,218,92,36,37,130,2,201,241,182,36,31,104,164,95,29,73,231,87,50,174,142,209,72,31,75,48,13,70,237,118,193,39,85,97,88,228,50,77,163,209,112,7,202,214,212,235,15,224,247,229,179,101,15,72,130,125,8,62,227,46,20,109,53,26,168,10,237,222,85,169,133,181,196,25,36,112,182,41,208,39,132,100,181,199,189,44,99,238,140,6,187,19,197,99,93,243,63,159,132,211,0,230,118,153,54,
|
||||
/* pair 7 */
|
||||
31,60,154,8,188,169,224,107,69,183,223,15,60,32,61,51,81,226,85,38,72,88,241,202,216,204,253,98,0,250,116,167,21,255,0,81,80,3,108,196,240,102,114,33,33,122,116,155,188,19,232,217,42,217,54,195,91,187,88,188,249,218,240,146,
|
||||
12,28,171,60,8,166,151,19,125,237,128,127,207,183,19,1,188,189,105,181,170,172,8,180,30,175,4,108,191,252,197,161,37,122,14,151,117,34,172,227,236,154,84,99,189,197,91,46,43,148,174,218,83,61,196,48,131,45,242,61,92,242,56,251,39,125,111,11,24,37,76,62,151,59,183,3,156,187,249,232,229,56,230,171,55,2,246,70,74,102,0,156,185,237,126,90,0,30,248,164,199,146,66,237,158,134,139,168,128,189,126,55,35,198,48,18,112,40,63,70,254,246,88,111,254,67,213,223,
|
||||
/* pair 8 */
|
||||
27,106,52,232,120,148,201,234,161,123,171,160,223,151,6,105,206,47,94,147,47,22,27,21,248,20,223,51,116,192,29,221,25,149,109,33,131,198,32,101,157,94,62,164,205,151,23,108,214,43,231,7,95,228,183,1,242,205,19,62,124,79,48,203,
|
||||
37,186,150,204,63,241,145,219,169,250,247,76,247,18,135,175,140,58,209,133,113,144,185,191,101,197,252,253,50,126,188,177,45,103,105,194,21,229,145,210,89,135,244,248,238,64,102,155,129,232,252,32,208,82,51,131,113,100,25,174,253,19,211,18,6,77,66,232,173,42,146,120,106,72,92,144,51,233,117,184,113,60,33,118,209,83,119,93,170,253,126,41,58,13,85,111,30,233,117,238,183,18,219,38,216,163,244,98,219,254,156,189,57,246,220,178,17,190,88,84,13,41,8,236,181,155,85,198,
|
||||
/* pair 9 */
|
||||
25,62,182,170,104,140,135,90,37,150,0,77,2,77,146,71,54,101,113,69,177,216,157,4,229,213,33,215,169,99,150,91,5,185,157,10,152,12,220,171,39,188,1,48,87,129,192,101,36,179,99,212,123,207,13,76,89,78,8,154,75,239,117,189,
|
||||
19,87,226,242,101,183,176,42,195,135,40,225,195,207,13,62,60,37,28,251,13,165,96,198,173,250,251,107,25,141,77,68,45,115,128,233,135,104,231,12,192,206,60,249,137,191,114,141,3,235,34,189,208,170,23,59,231,12,197,116,5,188,52,20,11,153,186,15,96,240,54,123,212,242,168,141,151,187,17,38,185,238,196,242,26,194,193,18,34,107,95,238,108,154,140,224,13,76,71,149,81,56,85,83,56,59,203,183,170,10,167,200,128,135,105,19,93,203,131,146,116,209,62,27,81,80,234,172,
|
||||
/* pair 10 */
|
||||
30,204,212,77,212,159,135,173,195,194,165,112,62,248,180,204,66,73,253,99,65,111,39,171,19,211,171,203,35,66,146,20,33,241,46,6,167,133,80,76,238,165,59,232,120,58,211,157,50,212,86,191,95,6,134,164,36,227,79,58,119,98,108,171,
|
||||
48,49,12,141,166,151,158,56,136,255,197,138,114,195,39,59,71,236,82,57,149,249,170,55,187,95,193,171,14,124,45,87,7,157,47,178,153,237,194,157,142,194,100,14,40,51,61,201,244,93,61,196,154,59,14,135,209,72,102,186,14,228,228,152,40,246,109,82,93,249,92,105,191,121,77,108,20,87,3,87,167,173,171,255,189,34,155,239,218,95,181,153,222,20,120,195,27,28,47,82,113,3,218,129,54,210,185,165,206,99,126,61,217,19,237,5,12,90,148,246,128,231,63,53,37,223,204,195
|
||||
};
|
||||
|
||||
// benchmarking 1 pair of points
|
||||
bytes g1_g2_1_pair;
|
||||
g1_g2_1_pair.insert(g1_g2_1_pair.begin(), g1_g2_pairs_raw.begin(), g1_g2_pairs_raw.begin() + 384);
|
||||
auto f_1_pair = [&]() {
|
||||
auto res = fc::alt_bn128_pair(g1_g2_1_pair, [](){});
|
||||
if (std::holds_alternative<fc::alt_bn128_error>(res)) {
|
||||
std::cout << "alt_bn128_pair 1 pair failed: "
|
||||
<< (int)std::get<fc::alt_bn128_error>(res) << std::endl;
|
||||
}
|
||||
};
|
||||
benchmarking("alt_bn128_pair (1 pair)", f_1_pair);
|
||||
|
||||
// benchmarking 10 pair of points
|
||||
bytes g1_g2_10_pairs;
|
||||
g1_g2_10_pairs.insert(g1_g2_10_pairs.begin(), g1_g2_pairs_raw.begin(), g1_g2_pairs_raw.end());
|
||||
auto f_10_pairs = [&]() {
|
||||
auto res = fc::alt_bn128_pair(g1_g2_10_pairs, [](){});
|
||||
if (std::holds_alternative<fc::alt_bn128_error>(res)) {
|
||||
std::cout << "alt_bn128_pair 10 pairs failed: "
|
||||
<< (int)std::get<fc::alt_bn128_error>(res) << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
benchmarking("alt_bn128_pair (10 pairs)", f_10_pairs);
|
||||
}
|
||||
|
||||
void alt_bn_128_benchmarking() {
|
||||
add_benchmarking();
|
||||
mul_benchmarking();
|
||||
pair_benchmarking();
|
||||
}
|
||||
|
||||
} // benchmark
|
||||
@@ -1,82 +0,0 @@
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <locale>
|
||||
|
||||
#include <benchmark.hpp>
|
||||
|
||||
namespace benchmark {
|
||||
|
||||
// update this map when a new feature is supported
|
||||
// key is the name and value is the function doing benchmarking
|
||||
std::map<std::string, std::function<void()>> features {
|
||||
{ "alt_bn_128", alt_bn_128_benchmarking },
|
||||
{ "modexp", modexp_benchmarking },
|
||||
{ "key", key_benchmarking },
|
||||
{ "hash", hash_benchmarking },
|
||||
{ "blake2", blake2_benchmarking },
|
||||
};
|
||||
|
||||
// values to control cout format
|
||||
constexpr auto name_width = 28;
|
||||
constexpr auto runs_width = 5;
|
||||
constexpr auto time_width = 12;
|
||||
constexpr auto ns_width = 2;
|
||||
|
||||
uint32_t num_runs = 1;
|
||||
|
||||
std::map<std::string, std::function<void()>> get_features() {
|
||||
return features;
|
||||
}
|
||||
|
||||
void set_num_runs(uint32_t runs) {
|
||||
num_runs = runs;
|
||||
}
|
||||
|
||||
void print_header() {
|
||||
std::cout << std::left << std::setw(name_width) << "function"
|
||||
<< std::setw(runs_width) << "runs"
|
||||
<< std::setw(time_width + ns_width) << std::right << "average"
|
||||
<< std::setw(time_width + ns_width) << "minimum"
|
||||
<< std::setw(time_width + ns_width) << "maximum"
|
||||
<< std::endl << std::endl;
|
||||
}
|
||||
|
||||
void print_results(std::string name, uint32_t runs, uint64_t total, uint64_t min, uint64_t max) {
|
||||
std::cout.imbue(std::locale(""));
|
||||
std::cout
|
||||
<< std::setw(name_width) << std::left << name
|
||||
<< std::setw(runs_width) << runs
|
||||
// std::fixed for not printing 1234 in 1.234e3.
|
||||
// setprecision(0) for not printing fractions
|
||||
<< std::right << std::fixed << std::setprecision(0)
|
||||
<< std::setw(time_width) << total/runs << std::setw(ns_width) << " ns"
|
||||
<< std::setw(time_width) << min << std::setw(ns_width) << " ns"
|
||||
<< std::setw(time_width) << max << std::setw(ns_width) << " ns"
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
bytes to_bytes(const std::string& source) {
|
||||
bytes output(source.length()/2);
|
||||
fc::from_hex(source, output.data(), output.size());
|
||||
return output;
|
||||
};
|
||||
|
||||
void benchmarking(std::string name, const std::function<void()>& func) {
|
||||
uint64_t total {0}, min {std::numeric_limits<uint64_t>::max()}, max {0};
|
||||
|
||||
for (auto i = 0U; i < num_runs; ++i) {
|
||||
auto start_time = std::chrono::high_resolution_clock::now();
|
||||
func();
|
||||
auto end_time = std::chrono::high_resolution_clock::now();
|
||||
|
||||
uint64_t duration = std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time).count();
|
||||
total += duration;
|
||||
min = std::min(min, duration);
|
||||
max = std::max(max, duration);
|
||||
}
|
||||
|
||||
print_results(name, num_runs, total, min, max);
|
||||
}
|
||||
|
||||
} // benchmark
|
||||
@@ -1,25 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include <fc/crypto/hex.hpp>
|
||||
|
||||
namespace benchmark {
|
||||
using bytes = std::vector<char>;
|
||||
|
||||
void set_num_runs(uint32_t runs);
|
||||
std::map<std::string, std::function<void()>> get_features();
|
||||
void print_header();
|
||||
bytes to_bytes(const std::string& source);
|
||||
|
||||
void alt_bn_128_benchmarking();
|
||||
void modexp_benchmarking();
|
||||
void key_benchmarking();
|
||||
void hash_benchmarking();
|
||||
void blake2_benchmarking();
|
||||
|
||||
void benchmarking(std::string name, const std::function<void()>& func);
|
||||
|
||||
} // benchmark
|
||||
@@ -1,21 +0,0 @@
|
||||
#include <fc/crypto/blake2.hpp>
|
||||
|
||||
#include <benchmark.hpp>
|
||||
|
||||
namespace benchmark {
|
||||
|
||||
void blake2_benchmarking() {
|
||||
uint32_t _rounds = 0x0C;
|
||||
bytes _h = to_bytes( "48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b");
|
||||
bytes _m = to_bytes("6162630000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
|
||||
bytes _t0_offset = to_bytes("0300000000000000");
|
||||
bytes _t1_offset = to_bytes("0000000000000000");
|
||||
bool _f = false;
|
||||
|
||||
auto blake2_f = [&]() {
|
||||
fc::blake2b(_rounds, _h, _m, _t0_offset, _t1_offset, _f, [](){});;
|
||||
};
|
||||
benchmarking("blake2", blake2_f);
|
||||
}
|
||||
|
||||
} // benchmark
|
||||
@@ -1,89 +0,0 @@
|
||||
#include <fc/crypto/hex.hpp>
|
||||
#include <fc/crypto/sha1.hpp>
|
||||
#include <fc/crypto/sha3.hpp>
|
||||
#include <fc/crypto/sha256.hpp>
|
||||
#include <fc/crypto/sha512.hpp>
|
||||
#include <fc/crypto/ripemd160.hpp>
|
||||
#include <fc/utility.hpp>
|
||||
|
||||
#include <benchmark.hpp>
|
||||
|
||||
using namespace fc;
|
||||
|
||||
namespace benchmark {
|
||||
|
||||
void hash_benchmarking() {
|
||||
std::string small_message = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ01";
|
||||
|
||||
// build a large message
|
||||
constexpr auto large_msg_size = 4096;
|
||||
std::string large_message;
|
||||
large_message.reserve(large_msg_size);
|
||||
uint32_t num_concats = large_msg_size/small_message.length();
|
||||
for (uint32_t i = 0; i < num_concats; ++i) {
|
||||
large_message += small_message;
|
||||
}
|
||||
|
||||
auto sha1_small_msg = [&]() {
|
||||
fc::sha1::hash(small_message);
|
||||
};
|
||||
benchmarking("sha1 (" + std::to_string(small_message.length()) + " bytes)", sha1_small_msg);
|
||||
|
||||
auto sha1_large_msg = [&]() {
|
||||
fc::sha1::hash(large_message);
|
||||
};
|
||||
benchmarking("sha1 (" + std::to_string(large_message.length()) + " bytes)", sha1_large_msg);
|
||||
|
||||
auto sha256_small_msg = [&]() {
|
||||
fc::sha256::hash(small_message);
|
||||
};
|
||||
benchmarking("sha256 (" + std::to_string(small_message.length()) + " bytes)", sha256_small_msg);
|
||||
|
||||
auto sha256_large_msg = [&]() {
|
||||
fc::sha256::hash(large_message);
|
||||
};
|
||||
benchmarking("sha256 (" + std::to_string(large_message.length()) + " bytes)", sha256_large_msg);
|
||||
|
||||
auto sha512_small_msg = [&]() {
|
||||
fc::sha512::hash(small_message);
|
||||
};
|
||||
benchmarking("sha512 (" + std::to_string(small_message.length()) + " bytes)", sha512_small_msg);
|
||||
|
||||
auto sha512_large_msg = [&]() {
|
||||
fc::sha512::hash(large_message);
|
||||
};
|
||||
benchmarking("sha512 (" + std::to_string(large_message.length()) + " bytes)", sha512_large_msg);
|
||||
|
||||
auto ripemd160_small_msg = [&]() {
|
||||
fc::ripemd160::hash(small_message);
|
||||
};
|
||||
benchmarking("ripemd160 (" + std::to_string(small_message.length()) + " bytes)", ripemd160_small_msg);
|
||||
|
||||
auto ripemd160_large_msg = [&]() {
|
||||
fc::ripemd160::hash(large_message);
|
||||
};
|
||||
benchmarking("ripemd160 (" + std::to_string(large_message.length()) + " bytes)", ripemd160_large_msg);
|
||||
|
||||
auto sha3_small_msg = [&]() {
|
||||
fc::sha3::hash(small_message, true);
|
||||
};
|
||||
benchmarking("sha3-256 (" + std::to_string(small_message.length()) + " bytes)", sha3_small_msg);
|
||||
|
||||
auto sha3_large_msg = [&]() {
|
||||
fc::sha3::hash(large_message, true);
|
||||
};
|
||||
benchmarking("sha3-256 (" + std::to_string(large_message.length()) + " bytes)", sha3_large_msg);
|
||||
|
||||
auto keccak_small_msg = [&]() {
|
||||
fc::sha3::hash(small_message, false);
|
||||
};
|
||||
benchmarking("keccak256 (" + std::to_string(small_message.length()) + " bytes)", keccak_small_msg);
|
||||
|
||||
auto keccak_large_msg = [&]() {
|
||||
fc::sha3::hash(large_message, false);
|
||||
};
|
||||
benchmarking("keccak256 (" + std::to_string(large_message.length()) + " bytes)", keccak_large_msg);
|
||||
|
||||
}
|
||||
|
||||
} // benchmark
|
||||
@@ -1,109 +0,0 @@
|
||||
#include <fc/crypto/public_key.hpp>
|
||||
#include <fc/crypto/private_key.hpp>
|
||||
#include <fc/crypto/signature.hpp>
|
||||
#include <fc/crypto/k1_recover.hpp>
|
||||
|
||||
#include <benchmark.hpp>
|
||||
|
||||
using namespace fc::crypto;
|
||||
using namespace fc;
|
||||
using namespace std::literals;
|
||||
|
||||
namespace benchmark {
|
||||
|
||||
void k1_sign_benchmarking() {
|
||||
auto payload = "Test Cases";
|
||||
auto digest = sha256::hash(payload, const_strlen(payload));
|
||||
auto private_key_string = std::string("5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3");
|
||||
auto key = private_key(private_key_string);
|
||||
|
||||
auto sign_non_canonical_f = [&]() {
|
||||
key.sign(digest, false);
|
||||
};
|
||||
benchmarking("k1_sign_non_canonical", sign_non_canonical_f);
|
||||
}
|
||||
|
||||
void k1_recover_benchmarking() {
|
||||
auto signature = to_bytes( "1b323dd47a1dd5592c296ee2ee12e0af38974087a475e99098a440284f19c1f7642fa0baa10a8a3ab800dfdbe987dee68a09b6fa3db45a5cc4f3a5835a1671d4dd");
|
||||
auto digest = to_bytes( "92390316873c5a9d520b28aba61e7a8f00025ac069acd9c4d2a71d775a55fa5f");
|
||||
|
||||
auto recover_f = [&]() {
|
||||
fc::k1_recover(signature, digest);
|
||||
};
|
||||
benchmarking("k1_recover", recover_f);
|
||||
}
|
||||
|
||||
void k1_benchmarking() {
|
||||
k1_sign_benchmarking();
|
||||
k1_recover_benchmarking();
|
||||
}
|
||||
|
||||
void r1_benchmarking() {
|
||||
auto payload = "Test Cases";
|
||||
auto digest = sha256::hash(payload, const_strlen(payload));
|
||||
auto key = private_key::generate<r1::private_key_shim>();
|
||||
|
||||
auto sign_f = [&]() {
|
||||
key.sign(digest);
|
||||
};
|
||||
benchmarking("r1_sign", sign_f);
|
||||
|
||||
auto sig = key.sign(digest);
|
||||
auto recover_f = [&]() {
|
||||
public_key(sig, digest);;
|
||||
};
|
||||
benchmarking("r1_recover", recover_f);
|
||||
}
|
||||
|
||||
static fc::crypto::webauthn::signature make_webauthn_sig(const fc::crypto::r1::private_key& priv_key,
|
||||
std::vector<uint8_t>& auth_data,
|
||||
const std::string& json) {
|
||||
|
||||
//webauthn signature is sha256(auth_data || client_data_hash)
|
||||
fc::sha256 client_data_hash = fc::sha256::hash(json);
|
||||
fc::sha256::encoder e;
|
||||
e.write((char*)auth_data.data(), auth_data.size());
|
||||
e.write(client_data_hash.data(), client_data_hash.data_size());
|
||||
|
||||
r1::compact_signature sig = priv_key.sign_compact(e.result());
|
||||
|
||||
char buff[8192];
|
||||
datastream<char*> ds(buff, sizeof(buff));
|
||||
fc::raw::pack(ds, sig);
|
||||
fc::raw::pack(ds, auth_data);
|
||||
fc::raw::pack(ds, json);
|
||||
ds.seekp(0);
|
||||
|
||||
fc::crypto::webauthn::signature ret;
|
||||
fc::raw::unpack(ds, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void wa_benchmarking() {
|
||||
static const r1::private_key priv = fc::crypto::r1::private_key::generate();
|
||||
static const fc::sha256 d = fc::sha256::hash("sup"s);
|
||||
static const fc::sha256 origin_hash = fc::sha256::hash("fctesting.invalid"s);
|
||||
std::string json = "{\"origin\":\"https://fctesting.invalid\",\"type\":\"webauthn.get\", \"challenge\":\"" + fc::base64url_encode(d.data(), d.data_size()) + "\"}";
|
||||
std::vector<uint8_t> auth_data(37);
|
||||
memcpy(auth_data.data(), origin_hash.data(), sizeof(origin_hash));
|
||||
|
||||
auto sign = [&]() {
|
||||
make_webauthn_sig(priv, auth_data, json);
|
||||
};
|
||||
benchmarking("webauthn_sign", sign);
|
||||
|
||||
auto sig = make_webauthn_sig(priv, auth_data, json);
|
||||
auto recover= [&]() {
|
||||
sig.recover(d, true);
|
||||
};
|
||||
benchmarking("webauthn_recover", recover);
|
||||
}
|
||||
|
||||
void key_benchmarking() {
|
||||
k1_benchmarking();
|
||||
r1_benchmarking();
|
||||
wa_benchmarking();
|
||||
}
|
||||
|
||||
} // benchmark
|
||||
@@ -1,80 +0,0 @@
|
||||
#include <iostream>
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
#include <benchmark.hpp>
|
||||
|
||||
namespace bpo = boost::program_options;
|
||||
using bpo::options_description;
|
||||
using bpo::variables_map;
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
uint32_t num_runs = 1;
|
||||
std::string feature_name;
|
||||
|
||||
auto features = benchmark::get_features();
|
||||
|
||||
options_description cli ("benchmark command line options");
|
||||
cli.add_options()
|
||||
("feature,f", bpo::value<std::string>(), "feature to be benchmarked; if this option is not present, all features are benchmarked.")
|
||||
("list,l", "list of supported features")
|
||||
("runs,r", bpo::value<uint32_t>(&num_runs)->default_value(1000), "the number of times running a function during benchmarking")
|
||||
("help,h", "benchmark functions, and report average, minimum, and maximum execution time in nanoseconds");
|
||||
|
||||
variables_map vmap;
|
||||
try {
|
||||
bpo::store(bpo::parse_command_line(argc, argv, cli), vmap);
|
||||
bpo::notify(vmap);
|
||||
|
||||
if (vmap.count("help") > 0) {
|
||||
cli.print(std::cerr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vmap.count("list") > 0) {
|
||||
auto first = true;
|
||||
std::cout << "Supported features are ";
|
||||
for (auto& [name, f]: features) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
std::cout << ", ";
|
||||
}
|
||||
std::cout << name;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vmap.count("feature") > 0) {
|
||||
feature_name = vmap["feature"].as<std::string>();
|
||||
if (features.find(feature_name) == features.end()) {
|
||||
std::cout << feature_name << " is not supported" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
} catch (bpo::unknown_option &ex) {
|
||||
std::cerr << ex.what() << std::endl;
|
||||
cli.print (std::cerr);
|
||||
return 1;
|
||||
} catch( ... ) {
|
||||
std::cerr << "unknown exception" << std::endl;
|
||||
}
|
||||
|
||||
benchmark::set_num_runs(num_runs);
|
||||
benchmark::print_header();
|
||||
|
||||
if (feature_name.empty()) {
|
||||
for (auto& [name, f]: features) {
|
||||
std::cout << name << ":" << std::endl;
|
||||
f();
|
||||
std::cout << std::endl;
|
||||
}
|
||||
} else {
|
||||
std::cout << feature_name << ":" << std::endl;
|
||||
features[feature_name]();
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
#include <fc/crypto/modular_arithmetic.hpp>
|
||||
|
||||
#include <random>
|
||||
|
||||
#include <benchmark.hpp>
|
||||
|
||||
namespace benchmark {
|
||||
|
||||
void modexp_benchmarking() {
|
||||
std::mt19937 r(0x11223344);
|
||||
|
||||
auto generate_random_bytes = [](std::mt19937& rand_eng, unsigned int num_bytes) {
|
||||
std::vector<char> result(num_bytes);
|
||||
|
||||
uint_fast32_t v = 0;
|
||||
for(int byte_pos = 0, end = result.size(); byte_pos < end; ++byte_pos) {
|
||||
if ((byte_pos & 0x03) == 0) { // if divisible by 4
|
||||
v = rand_eng();
|
||||
}
|
||||
result[byte_pos] = v & 0xFF;
|
||||
v >>= 8;
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
static constexpr unsigned int start_num_bytes = 128; // 64
|
||||
static constexpr unsigned int end_num_bytes = 256; // 512
|
||||
static constexpr unsigned int delta_num_bytes = 128; // 64
|
||||
|
||||
static_assert(start_num_bytes <= end_num_bytes);
|
||||
static_assert(delta_num_bytes > 0);
|
||||
static_assert((end_num_bytes - start_num_bytes) % delta_num_bytes == 0);
|
||||
|
||||
for (unsigned int n = start_num_bytes, slot = 0; n <= end_num_bytes; n += delta_num_bytes, ++slot) {
|
||||
auto base = generate_random_bytes(r, n);
|
||||
auto exponent = generate_random_bytes(r, n);
|
||||
auto modulus = generate_random_bytes(r, n);
|
||||
|
||||
auto f = [&]() {
|
||||
fc::modexp(base, exponent, modulus);
|
||||
};
|
||||
|
||||
benchmarking(std::to_string(n*8) + " bit width", f);
|
||||
}
|
||||
|
||||
// Running the above benchmark (using commented values for num_trials and *_num_bytes) with a release build on an AMD 3.4 GHz CPU
|
||||
// provides average durations for executing mod_exp for increasing bit sizes for the value.
|
||||
|
||||
// For example: with 512-bit values, the average duration is approximately 40 microseconds; with 1024-bit values, the average duration
|
||||
// is approximately 260 microseconds; with 2048-bit values, the average duration is approximately 2 milliseconds; and, with 4096-bit
|
||||
// values, the average duration is approximately 14 milliseconds.
|
||||
|
||||
// It appears that a model of the average time that scales quadratically with the bit size fits the empirically generated data well.
|
||||
// TODO: See if theoretical analysis of the modular exponentiation algorithm also justifies quadratic scaling.
|
||||
}
|
||||
|
||||
} // benchmark
|
||||
@@ -2,19 +2,19 @@
|
||||
content_title: Build Antelope from Source
|
||||
---
|
||||
|
||||
The shell scripts previously recommended for building the software have been removed in favor of a build process entirely driven by CMake. Those wishing to build from source are now responsible for installing the necessary dependencies. The list of dependencies and the recommended build procedure are in the [`README.md`](https://github.com/AntelopeIO/leap/blob/release/3.2/README.md) file. Instructions are also included for efficiently running the tests.
|
||||
The shell scripts previously recommended for building the software have been removed in favor of a build process entirely driven by CMake. Those wishing to build from source are now responsible for installing the necessary dependencies. The list of dependencies and the recommended build procedure are in the [`README.md`](https://github.com/AntelopeIO/leap/blob/release/3.1/README.md) file. Instructions are also included for efficiently running the tests.
|
||||
|
||||
### Using DUNE
|
||||
As an alternative to building from source, try [Docker Utilities for Node Execution](https://github.com/AntelopeIO/DUNE) for the easiest way to get started and for multi-platform support.
|
||||
|
||||
### Building From Source
|
||||
You can also build and install Leap from source. Instructions for that currently live [here](https://github.com/AntelopeIO/leap/blob/release/3.2/README.md#build-and-install-from-source).
|
||||
You can also build and install Leap from source. Instructions for that currently live [here](https://github.com/AntelopeIO/leap/blob/release/3.1/README.md#build-and-install-from-source).
|
||||
|
||||
#### Building Pinned Build Binary Packages
|
||||
The pinned build instructions have moved [here](https://github.com/AntelopeIO/leap/blob/release/3.2/README.md#pinned-build). You may want to look at the [prerequisites](https://github.com/AntelopeIO/leap/blob/release/3.2/README.md#prerequisites) and our warning on parallelization using the `-j` jobs flag [here](https://github.com/AntelopeIO/leap/blob/release/3.2/README.md#step-3---build) before you build.
|
||||
The pinned build instructions have moved [here](https://github.com/AntelopeIO/leap/blob/release/3.1/README.md#pinned-build). You may want to look at the [prerequisites](https://github.com/AntelopeIO/leap/blob/release/3.1/README.md#prerequisites) and our warning on parallelization using the `-j` jobs flag [here](https://github.com/AntelopeIO/leap/blob/release/3.1/README.md#step-3---build) before you build.
|
||||
|
||||
#### Manual (non "pinned") Build Instructions
|
||||
The unpinned build instructions have moved [here](https://github.com/AntelopeIO/leap/blob/release/3.2/README.md#unpinned-build). You may want to look at the [prerequisites](https://github.com/AntelopeIO/leap/blob/release/3.2/README.md#prerequisites) and our warning on parallelization using the `-j` jobs flag [here](https://github.com/AntelopeIO/leap/blob/release/3.2/README.md#step-3---build) before you build.
|
||||
The unpinned build instructions have moved [here](https://github.com/AntelopeIO/leap/blob/release/3.1/README.md#unpinned-build). You may want to look at the [prerequisites](https://github.com/AntelopeIO/leap/blob/release/3.1/README.md#prerequisites) and our warning on parallelization using the `-j` jobs flag [here](https://github.com/AntelopeIO/leap/blob/release/3.1/README.md#step-3---build) before you build.
|
||||
|
||||
### Running Tests
|
||||
Documentation on available test suites and how to run them has moved [here](https://github.com/AntelopeIO/leap/blob/release/3.2/README.md#test).
|
||||
Documentation on available test suites and how to run them has moved [here](https://github.com/AntelopeIO/leap/blob/release/3.1/README.md#test).
|
||||
|
||||
@@ -21,33 +21,35 @@ These can only be specified from the `nodeos` command-line:
|
||||
```console
|
||||
Command Line Options for eosio::chain_plugin:
|
||||
--genesis-json arg File to read Genesis State from
|
||||
--genesis-timestamp arg override the initial timestamp in the
|
||||
--genesis-timestamp arg override the initial timestamp in the
|
||||
Genesis State file
|
||||
--print-genesis-json extract genesis_state from blocks.log
|
||||
--print-genesis-json extract genesis_state from blocks.log
|
||||
as JSON, print to console, and exit
|
||||
--extract-genesis-json arg extract genesis_state from blocks.log
|
||||
--extract-genesis-json arg extract genesis_state from blocks.log
|
||||
as JSON, write into specified file, and
|
||||
exit
|
||||
--print-build-info print build environment information to
|
||||
--print-build-info print build environment information to
|
||||
console as JSON and exit
|
||||
--extract-build-info arg extract build environment information
|
||||
--extract-build-info arg extract build environment information
|
||||
as JSON, write into specified file, and
|
||||
exit
|
||||
--force-all-checks do not skip any checks that can be
|
||||
skipped while replaying irreversible
|
||||
blocks
|
||||
--force-all-checks do not skip any validation checks while
|
||||
replaying blocks (useful for replaying
|
||||
blocks from untrusted source)
|
||||
--disable-replay-opts disable optimizations that specifically
|
||||
target replay
|
||||
--replay-blockchain clear chain state database and replay
|
||||
--replay-blockchain clear chain state database and replay
|
||||
all blocks
|
||||
--hard-replay-blockchain clear chain state database, recover as
|
||||
many blocks as possible from the block
|
||||
--hard-replay-blockchain clear chain state database, recover as
|
||||
many blocks as possible from the block
|
||||
log, and then replay those blocks
|
||||
--delete-all-blocks clear chain state database and block
|
||||
--delete-all-blocks clear chain state database and block
|
||||
log
|
||||
--truncate-at-block arg (=0) stop hard replay / block log recovery
|
||||
at this block number (if set to
|
||||
--truncate-at-block arg (=0) stop hard replay / block log recovery
|
||||
at this block number (if set to
|
||||
non-zero number)
|
||||
--terminate-at-block arg (=0) terminate after reaching this block
|
||||
number (if set to a non-zero number)
|
||||
--snapshot arg File to read Snapshot State from
|
||||
|
||||
```
|
||||
@@ -58,162 +60,170 @@ These can be specified from both the `nodeos` command-line or the `config.ini` f
|
||||
|
||||
```console
|
||||
Config Options for eosio::chain_plugin:
|
||||
--blocks-dir arg (="blocks") the location of the blocks directory
|
||||
(absolute path or relative to
|
||||
--blocks-dir arg (="blocks") the location of the blocks directory
|
||||
(absolute path or relative to
|
||||
application data dir)
|
||||
--protocol-features-dir arg (="protocol_features")
|
||||
the location of the protocol_features
|
||||
the location of the protocol_features
|
||||
directory (absolute path or relative to
|
||||
application config dir)
|
||||
--checkpoint arg Pairs of [BLOCK_NUM,BLOCK_ID] that
|
||||
--checkpoint arg Pairs of [BLOCK_NUM,BLOCK_ID] that
|
||||
should be enforced as checkpoints.
|
||||
--wasm-runtime runtime (=eos-vm-jit) Override default WASM runtime (
|
||||
--wasm-runtime runtime (=eos-vm-jit) Override default WASM runtime (
|
||||
"eos-vm-jit", "eos-vm")
|
||||
"eos-vm-jit" : A WebAssembly runtime
|
||||
that compiles WebAssembly code to
|
||||
"eos-vm-jit" : A WebAssembly runtime
|
||||
that compiles WebAssembly code to
|
||||
native x86 code prior to execution.
|
||||
"eos-vm" : A WebAssembly interpreter.
|
||||
|
||||
--profile-account arg The name of an account whose code will
|
||||
|
||||
--profile-account arg The name of an account whose code will
|
||||
be profiled
|
||||
--abi-serializer-max-time-ms arg (=15)
|
||||
Override default maximum ABI
|
||||
Override default maximum ABI
|
||||
serialization time allowed in ms
|
||||
--chain-state-db-size-mb arg (=1024) Maximum size (in MiB) of the chain
|
||||
--chain-state-db-size-mb arg (=1024) Maximum size (in MiB) of the chain
|
||||
state database
|
||||
--chain-state-db-guard-size-mb arg (=128)
|
||||
Safely shut down node when free space
|
||||
remaining in the chain state database
|
||||
Safely shut down node when free space
|
||||
remaining in the chain state database
|
||||
drops below this size (in MiB).
|
||||
--signature-cpu-billable-pct arg (=50)
|
||||
Percentage of actual signature recovery
|
||||
cpu to bill. Whole number percentages,
|
||||
cpu to bill. Whole number percentages,
|
||||
e.g. 50 for 50%
|
||||
--chain-threads arg (=2) Number of worker threads in controller
|
||||
--chain-threads arg (=2) Number of worker threads in controller
|
||||
thread pool
|
||||
--contracts-console print contract's output to console
|
||||
--deep-mind print deeper information about chain
|
||||
--deep-mind print deeper information about chain
|
||||
operations
|
||||
--actor-whitelist arg Account added to actor whitelist (may
|
||||
--actor-whitelist arg Account added to actor whitelist (may
|
||||
specify multiple times)
|
||||
--actor-blacklist arg Account added to actor blacklist (may
|
||||
--actor-blacklist arg Account added to actor blacklist (may
|
||||
specify multiple times)
|
||||
--contract-whitelist arg Contract account added to contract
|
||||
--contract-whitelist arg Contract account added to contract
|
||||
whitelist (may specify multiple times)
|
||||
--contract-blacklist arg Contract account added to contract
|
||||
--contract-blacklist arg Contract account added to contract
|
||||
blacklist (may specify multiple times)
|
||||
--action-blacklist arg Action (in the form code::action) added
|
||||
to action blacklist (may specify
|
||||
to action blacklist (may specify
|
||||
multiple times)
|
||||
--key-blacklist arg Public key added to blacklist of keys
|
||||
that should not be included in
|
||||
authorities (may specify multiple
|
||||
--key-blacklist arg Public key added to blacklist of keys
|
||||
that should not be included in
|
||||
authorities (may specify multiple
|
||||
times)
|
||||
--sender-bypass-whiteblacklist arg Deferred transactions sent by accounts
|
||||
in this list do not have any of the
|
||||
subjective whitelist/blacklist checks
|
||||
applied to them (may specify multiple
|
||||
--sender-bypass-whiteblacklist arg Deferred transactions sent by accounts
|
||||
in this list do not have any of the
|
||||
subjective whitelist/blacklist checks
|
||||
applied to them (may specify multiple
|
||||
times)
|
||||
--read-mode arg (=speculative) Database read mode ("speculative",
|
||||
--read-mode arg (=speculative) Database read mode ("speculative",
|
||||
"head", "read-only", "irreversible").
|
||||
In "speculative" mode: database
|
||||
contains state changes by transactions
|
||||
in the blockchain up to the head block
|
||||
as well as some transactions not yet
|
||||
In "speculative" mode: database
|
||||
contains state changes by transactions
|
||||
in the blockchain up to the head block
|
||||
as well as some transactions not yet
|
||||
included in the blockchain.
|
||||
In "head" mode: database contains state
|
||||
changes by only transactions in the
|
||||
blockchain up to the head block;
|
||||
transactions received by the node are
|
||||
changes by only transactions in the
|
||||
blockchain up to the head block;
|
||||
transactions received by the node are
|
||||
relayed if valid.
|
||||
In "read-only" mode: (DEPRECATED: see
|
||||
p2p-accept-transactions &
|
||||
api-accept-transactions) database
|
||||
contains state changes by only
|
||||
transactions in the blockchain up to
|
||||
the head block; transactions received
|
||||
In "read-only" mode: (DEPRECATED: see
|
||||
p2p-accept-transactions &
|
||||
api-accept-transactions) database
|
||||
contains state changes by only
|
||||
transactions in the blockchain up to
|
||||
the head block; transactions received
|
||||
via the P2P network are not relayed and
|
||||
transactions cannot be pushed via the
|
||||
transactions cannot be pushed via the
|
||||
chain API.
|
||||
In "irreversible" mode: database
|
||||
contains state changes by only
|
||||
transactions in the blockchain up to
|
||||
the last irreversible block;
|
||||
transactions received via the P2P
|
||||
network are not relayed and
|
||||
transactions cannot be pushed via the
|
||||
In "irreversible" mode: database
|
||||
contains state changes by only
|
||||
transactions in the blockchain up to
|
||||
the last irreversible block;
|
||||
transactions received via the P2P
|
||||
network are not relayed and
|
||||
transactions cannot be pushed via the
|
||||
chain API.
|
||||
|
||||
--api-accept-transactions arg (=1) Allow API transactions to be evaluated
|
||||
|
||||
--api-accept-transactions arg (=1) Allow API transactions to be evaluated
|
||||
and relayed if valid.
|
||||
--validation-mode arg (=full) Chain validation mode ("full" or
|
||||
--validation-mode arg (=full) Chain validation mode ("full" or
|
||||
"light").
|
||||
In "full" mode all incoming blocks will
|
||||
be fully validated.
|
||||
In "light" mode all incoming blocks
|
||||
headers will be fully validated;
|
||||
transactions in those validated blocks
|
||||
will be trusted
|
||||
|
||||
--disable-ram-billing-notify-checks Disable the check which subjectively
|
||||
In "light" mode all incoming blocks
|
||||
headers will be fully validated;
|
||||
transactions in those validated blocks
|
||||
will be trusted
|
||||
|
||||
--disable-ram-billing-notify-checks Disable the check which subjectively
|
||||
fails a transaction if a contract bills
|
||||
more RAM to another account within the
|
||||
more RAM to another account within the
|
||||
context of a notification handler (i.e.
|
||||
when the receiver is not the code of
|
||||
when the receiver is not the code of
|
||||
the action).
|
||||
--maximum-variable-signature-length arg (=16384)
|
||||
Subjectively limit the maximum length
|
||||
of variable components in a variable
|
||||
Subjectively limit the maximum length
|
||||
of variable components in a variable
|
||||
legnth signature to this size in bytes
|
||||
--trusted-producer arg Indicate a producer whose blocks
|
||||
headers signed by it will be fully
|
||||
validated, but transactions in those
|
||||
--trusted-producer arg Indicate a producer whose blocks
|
||||
headers signed by it will be fully
|
||||
validated, but transactions in those
|
||||
validated blocks will be trusted.
|
||||
--database-map-mode arg (=mapped) Database map mode ("mapped", "heap", or
|
||||
"locked").
|
||||
In "mapped" mode database is memory
|
||||
In "mapped" mode database is memory
|
||||
mapped as a file.
|
||||
In "heap" mode database is preloaded in
|
||||
to swappable memory and will use huge
|
||||
to swappable memory and will use huge
|
||||
pages if available.
|
||||
In "locked" mode database is preloaded,
|
||||
locked in to memory, and will use huge
|
||||
locked in to memory, and will use huge
|
||||
pages if available.
|
||||
|
||||
--enable-account-queries arg (=0) enable queries to find accounts by
|
||||
|
||||
--eos-vm-oc-cache-size-mb arg (=1024) Maximum size (in MiB) of the EOS VM OC
|
||||
code cache
|
||||
--eos-vm-oc-compile-threads arg (=1) Number of threads to use for EOS VM OC
|
||||
tier-up
|
||||
--eos-vm-oc-enable Enable EOS VM OC tier-up runtime
|
||||
--enable-account-queries arg (=0) enable queries to find accounts by
|
||||
various metadata.
|
||||
--max-nonprivileged-inline-action-size arg (=4096)
|
||||
maximum allowed size (in bytes) of an
|
||||
inline action for a nonprivileged
|
||||
maximum allowed size (in bytes) of an
|
||||
inline action for a nonprivileged
|
||||
account
|
||||
--transaction-retry-max-storage-size-gb arg
|
||||
Maximum size (in GiB) allowed to be
|
||||
allocated for the Transaction Retry
|
||||
feature. Setting above 0 enables this
|
||||
Maximum size (in GiB) allowed to be
|
||||
allocated for the Transaction Retry
|
||||
feature. Setting above 0 enables this
|
||||
feature.
|
||||
--transaction-retry-interval-sec arg (=20)
|
||||
How often, in seconds, to resend an
|
||||
incoming transaction to network if not
|
||||
How often, in seconds, to resend an
|
||||
incoming transaction to network if not
|
||||
seen in a block.
|
||||
--transaction-retry-max-expiration-sec arg (=90)
|
||||
Maximum allowed transaction expiration
|
||||
for retry transactions, will retry
|
||||
--transaction-retry-max-expiration-sec arg (=120)
|
||||
Maximum allowed transaction expiration
|
||||
for retry transactions, will retry
|
||||
transactions up to this value.
|
||||
--transaction-finality-status-max-storage-size-gb arg
|
||||
Maximum size (in GiB) allowed to be
|
||||
allocated for the Transaction Finality
|
||||
Maximum size (in GiB) allowed to be
|
||||
allocated for the Transaction Finality
|
||||
Status feature. Setting above 0 enables
|
||||
this feature.
|
||||
--transaction-finality-status-success-duration-sec arg (=180)
|
||||
Duration (in seconds) a successful
|
||||
transaction's Finality Status will
|
||||
remain available from being first
|
||||
Duration (in seconds) a successful
|
||||
transaction's Finality Status will
|
||||
remain available from being first
|
||||
identified.
|
||||
--transaction-finality-status-failure-duration-sec arg (=180)
|
||||
Duration (in seconds) a failed
|
||||
transaction's Finality Status will
|
||||
remain available from being first
|
||||
Duration (in seconds) a failed
|
||||
transaction's Finality Status will
|
||||
remain available from being first
|
||||
identified.
|
||||
--block-log-retain-blocks arg if set, periodically prune the block
|
||||
log to store only configured number of
|
||||
most recent blocks
|
||||
|
||||
```
|
||||
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
[[warning | Deprecation Notice]]
|
||||
| The `history_plugin` that the `history_api_plugin` depends upon is deprecated and will no longer be maintained. Please use the [`state_history_plugin`](../state_history_plugin/index.md) instead.
|
||||
|
||||
## Description
|
||||
|
||||
The `history_api_plugin` exposes functionality from the [`history_plugin`](../history_plugin/index.md) to the RPC API interface managed by the [`http_plugin`](../http_plugin/index.md), providing read-only access to blockchain data.
|
||||
|
||||
It provides four RPC API endpoints:
|
||||
|
||||
* get_actions
|
||||
* get_transaction
|
||||
* get_key_accounts
|
||||
* get_controlled_accounts
|
||||
|
||||
The four actions listed above are used by the following `cleos` commands (matching order):
|
||||
|
||||
* get actions
|
||||
* get transaction
|
||||
* get accounts
|
||||
* get servants
|
||||
|
||||
## Usage
|
||||
|
||||
```console
|
||||
# config.ini
|
||||
plugin = eosio::history_api_plugin
|
||||
```
|
||||
```sh
|
||||
# command-line
|
||||
nodeos ... --plugin eosio::history_api_plugin
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
None
|
||||
|
||||
## Dependencies
|
||||
|
||||
* [`history_plugin`](../history_plugin/index.md)
|
||||
* [`chain_plugin`](../chain_plugin/index.md)
|
||||
* [`http_plugin`](../http_plugin/index.md)
|
||||
|
||||
### Load Dependency Examples
|
||||
|
||||
```console
|
||||
# config.ini
|
||||
plugin = eosio::history_plugin
|
||||
[options]
|
||||
plugin = eosio::chain_plugin
|
||||
[options]
|
||||
plugin = eosio::http_plugin
|
||||
[options]
|
||||
```
|
||||
```sh
|
||||
# command-line
|
||||
nodeos ... --plugin eosio::history_plugin [options] \
|
||||
--plugin eosio::chain_plugin [operations] [options] \
|
||||
--plugin eosio::http_plugin [options]
|
||||
```
|
||||
@@ -1,41 +0,0 @@
|
||||
[[warning | Deprecation Notice]]
|
||||
| The `history_plugin` is deprecated and will no longer be maintained. Please use the [`state_history_plugin`](../state_history_plugin/index.md) instead.
|
||||
|
||||
## Description
|
||||
|
||||
The `history_plugin` provides a cache layer to obtain historical data about the blockchain objects. It depends on [`chain_plugin`](../chain_plugin/index.md) for the data.
|
||||
|
||||
## Usage
|
||||
|
||||
```console
|
||||
# config.ini
|
||||
plugin = eosio::history_plugin
|
||||
[options]
|
||||
```
|
||||
```sh
|
||||
# command-line
|
||||
nodeos ... --plugin eosio::history_plugin [options]
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
These can be specified from both the `nodeos` command-line or the `config.ini` file:
|
||||
|
||||
```console
|
||||
Config Options for eosio::history_plugin:
|
||||
-f [ --filter-on ] arg Track actions which match
|
||||
receiver:action:actor. Actor may be
|
||||
blank to include all. Action and Actor
|
||||
both blank allows all from Recieiver.
|
||||
Receiver may not be blank.
|
||||
-F [ --filter-out ] arg Do not track actions which match
|
||||
receiver:action:actor. Action and Actor
|
||||
both blank excludes all from Reciever.
|
||||
Actor blank excludes all from
|
||||
reciever:action. Receiver may not be
|
||||
blank.
|
||||
```
|
||||
|
||||
## Dependencies
|
||||
|
||||
* [`chain_plugin`](../chain_plugin/index.md)
|
||||
@@ -22,46 +22,47 @@ These can be specified from both the command-line or the `config.ini` file:
|
||||
|
||||
```console
|
||||
Config Options for eosio::http_plugin:
|
||||
--unix-socket-path arg The filename (relative to data-dir) to
|
||||
create a unix socket for HTTP RPC; set
|
||||
blank to disable (=keosd.sock for keosd)
|
||||
--http-server-address arg (=127.0.0.1:8888 for nodeos)
|
||||
The local IP and port to listen for
|
||||
--unix-socket-path arg The filename (relative to data-dir) to
|
||||
create a unix socket for HTTP RPC; set
|
||||
blank to disable.
|
||||
--http-server-address arg (=127.0.0.1:8888)
|
||||
The local IP and port to listen for
|
||||
incoming http connections; set blank to
|
||||
disable.
|
||||
--https-server-address arg The local IP and port to listen for
|
||||
--https-server-address arg The local IP and port to listen for
|
||||
incoming https connections; leave blank
|
||||
to disable.
|
||||
--https-certificate-chain-file arg Filename with the certificate chain to
|
||||
present on https connections. PEM
|
||||
--https-certificate-chain-file arg Filename with the certificate chain to
|
||||
present on https connections. PEM
|
||||
format. Required for https.
|
||||
--https-private-key-file arg Filename with https private key in PEM
|
||||
--https-private-key-file arg Filename with https private key in PEM
|
||||
format. Required for https
|
||||
--https-ecdh-curve arg (=secp384r1) Configure https ECDH curve to use:
|
||||
--https-ecdh-curve arg (=secp384r1) Configure https ECDH curve to use:
|
||||
secp384r1 or prime256v1
|
||||
--access-control-allow-origin arg Specify the Access-Control-Allow-Origin
|
||||
to be returned on each request.
|
||||
--access-control-allow-headers arg Specify the Access-Control-Allow-Header
|
||||
s to be returned on each request.
|
||||
--access-control-max-age arg Specify the Access-Control-Max-Age to
|
||||
--access-control-max-age arg Specify the Access-Control-Max-Age to
|
||||
be returned on each request.
|
||||
--access-control-allow-credentials Specify if Access-Control-Allow-Credent
|
||||
ials: true should be returned on each
|
||||
ials: true should be returned on each
|
||||
request.
|
||||
--max-body-size arg (=1048576) The maximum body size in bytes allowed
|
||||
--max-body-size arg (=2097152) The maximum body size in bytes allowed
|
||||
for incoming RPC requests
|
||||
--http-max-bytes-in-flight-mb arg (=500)
|
||||
Maximum size in megabytes http_plugin
|
||||
should use for processing http
|
||||
requests. 503 error response when
|
||||
exceeded.
|
||||
Maximum size in megabytes http_plugin
|
||||
should use for processing http
|
||||
requests. -1 for unlimited. 429 error
|
||||
response when exceeded.
|
||||
--http-max-response-time-ms arg (=30) Maximum time for processing a request.
|
||||
--verbose-http-errors Append the error log to HTTP responses
|
||||
--http-validate-host arg (=1) If set to false, then any incoming
|
||||
--http-validate-host arg (=1) If set to false, then any incoming
|
||||
"Host" header is considered valid
|
||||
--http-alias arg Additionaly acceptable values for the
|
||||
"Host" header of incoming HTTP
|
||||
requests, can be specified multiple
|
||||
times. Includes http/s_server_address
|
||||
--http-alias arg Additionaly acceptable values for the
|
||||
"Host" header of incoming HTTP
|
||||
requests, can be specified multiple
|
||||
times. Includes http/s_server_address
|
||||
by default.
|
||||
--http-threads arg (=2) Number of worker threads in http thread
|
||||
pool
|
||||
|
||||
@@ -44,7 +44,7 @@ Config Options for eosio::net_plugin:
|
||||
--p2p-accept-transactions arg (=1) Allow transactions received over p2p
|
||||
network to be evaluated and relayed if
|
||||
valid.
|
||||
--agent-name arg (="EOS Test Agent") The name supplied to identify this node
|
||||
--agent-name arg (=EOS Test Agent) The name supplied to identify this node
|
||||
amongst the peers.
|
||||
--allowed-connection arg (=any) Can be 'any' or 'producers' or
|
||||
'specified' or 'none'. If 'specified',
|
||||
@@ -73,13 +73,15 @@ Config Options for eosio::net_plugin:
|
||||
synchronization
|
||||
--use-socket-read-watermark arg (=0) Enable experimental socket read
|
||||
watermark optimization
|
||||
--peer-log-format arg (=["${_name}" ${_ip}:${_port}])
|
||||
--peer-log-format arg (=["${_name}" - ${_cid} ${_ip}:${_port}] )
|
||||
The string used to format peers when
|
||||
logging messages about them. Variables
|
||||
are escaped with ${<variable name>}.
|
||||
Available Variables:
|
||||
_name self-reported name
|
||||
|
||||
_cid assigned connection id
|
||||
|
||||
_id self-reported ID (64 hex
|
||||
characters)
|
||||
|
||||
@@ -94,7 +96,10 @@ Config Options for eosio::net_plugin:
|
||||
peer
|
||||
|
||||
_lport local port number connected
|
||||
to peer
|
||||
to peer
|
||||
--p2p-keepalive-interval-ms arg (=10000)
|
||||
peer heartbeat keepalive message
|
||||
interval in milliseconds
|
||||
```
|
||||
|
||||
## Dependencies
|
||||
|
||||
@@ -23,7 +23,6 @@ These can be specified from both the `nodeos` command-line or the `config.ini` f
|
||||
|
||||
```console
|
||||
Config Options for eosio::producer_plugin:
|
||||
|
||||
-e [ --enable-stale-production ] Enable block production, even if the
|
||||
chain is stale.
|
||||
-x [ --pause-on-startup ] Start this node in a state where
|
||||
@@ -49,7 +48,7 @@ Config Options for eosio::producer_plugin:
|
||||
<public-key>=<provider-spec>
|
||||
Where:
|
||||
<public-key> is a string form of
|
||||
a vaild Antelope public
|
||||
a valid EOS public
|
||||
key
|
||||
|
||||
<provider-spec> is a string in the
|
||||
@@ -59,7 +58,7 @@ Config Options for eosio::producer_plugin:
|
||||
<provider-type> is KEY, or KEOSD
|
||||
|
||||
KEY:<data> is a string form of
|
||||
a valid Antelope
|
||||
a valid EOS
|
||||
private key which
|
||||
maps to the provided
|
||||
public key
|
||||
@@ -119,11 +118,6 @@ Config Options for eosio::producer_plugin:
|
||||
Sets the maximum amount of failures
|
||||
that are allowed for a given account
|
||||
per block.
|
||||
Disregarded for accounts that have been
|
||||
whitelisted by disabling subjective
|
||||
billing for the account using the
|
||||
disable-subjective-account-billing
|
||||
configuration option.
|
||||
--subjective-account-decay-time-minutes arg (=1440)
|
||||
Sets the time to return full subjective
|
||||
cpu for accounts
|
||||
@@ -142,9 +136,6 @@ Config Options for eosio::producer_plugin:
|
||||
--disable-subjective-account-billing arg
|
||||
Account which is excluded from
|
||||
subjective CPU billing
|
||||
Account is considered whitelisted and
|
||||
will not be subject to enforcement of
|
||||
subjective-account-max-failures.
|
||||
--disable-subjective-p2p-billing arg (=1)
|
||||
Disable subjective CPU billing for P2P
|
||||
transactions
|
||||
|
||||
@@ -1,19 +1,10 @@
|
||||
|
||||
## Overview
|
||||
|
||||
The `resource_monitor_plugin` monitors space usage in the computing system where `nodeos` is running. Specifically, every `resource-monitor-interval-seconds` seconds,
|
||||
it measures the individual space used by each of the file systems mounted
|
||||
by `data-dir`, `state-dir`, `blocks-log-dir`, `snapshots-dir`,
|
||||
`state-history-dir`, and `trace-dir`.
|
||||
When space usage in any of the monitored file system is within `5%` of the threshold
|
||||
specified by `resource-monitor-space-threshold`, a warning containing the file system
|
||||
path and percentage of space has used is printed out.
|
||||
When space usage exceeds the threshold,
|
||||
if `resource-monitor-not-shutdown-on-threshold-exceeded` is not set,
|
||||
`nodeos` gracefully shuts down; if `resource-monitor-not-shutdown-on-threshold-exceeded` is set, `nodeos` prints out warnings periodically
|
||||
until space usage goes under the threshold.
|
||||
The `resource_monitor_plugin` monitors space usage in the computing system where `nodeos` is running. Specifically, every `resource-monitor-interval-seconds` seconds, it measures the individual space used by each of the file systems mounted by `data-dir`, `state-dir`, `blocks-log-dir`, `snapshots-dir`, `state-history-dir`, and `trace-dir`. When space usage in any of the monitored file system is within `5%` of the threshold specified by `resource-monitor-space-threshold`, a warning containing the file system path and percentage of space has used is printed out. When space usage exceeds the threshold, if `resource-monitor-not-shutdown-on-threshold-exceeded` is not set, `nodeos` gracefully shuts down; if `resource-monitor-not-shutdown-on-threshold-exceeded` is set, `nodeos` prints out warnings periodically until space usage goes under the threshold.
|
||||
|
||||
`resource_monitor_plugin` is always loaded.
|
||||
|
||||
## Usage
|
||||
|
||||
```console
|
||||
@@ -32,33 +23,28 @@ These can be specified from both the `nodeos` command-line or the `config.ini` f
|
||||
|
||||
```console
|
||||
Config Options for eosio::resource_monitor_plugin:
|
||||
|
||||
--resource-monitor-interval-seconds arg (=2)
|
||||
Time in seconds between two consecutive checks
|
||||
of space usage. Should be between 1 and 300.
|
||||
Time in seconds between two consecutive
|
||||
checks of resource usage. Should be
|
||||
between 1 and 300
|
||||
--resource-monitor-space-threshold arg (=90)
|
||||
Threshold in terms of percentage of used space
|
||||
vs total space. If the used space is within
|
||||
`5%` of the threshold, a warning is generated.
|
||||
If the used space is above the threshold and
|
||||
`resource-monitor-not-shutdown-on-threshold-exceeded`
|
||||
is enabled, a shutdown is initiated; otherwise
|
||||
a warning will be continuously printed out.
|
||||
The value should be between 6 and 99.
|
||||
Threshold in terms of percentage of
|
||||
used space vs total space. If used
|
||||
space is above (threshold - 5%), a
|
||||
warning is generated. Unless
|
||||
resource-monitor-not-shutdown-on-thresh
|
||||
old-exceeded is enabled, a graceful
|
||||
shutdown is initiated if used space is
|
||||
above the threshold. The value should
|
||||
be between 6 and 99
|
||||
--resource-monitor-not-shutdown-on-threshold-exceeded
|
||||
A switch used to indicate `nodeos` will "not"
|
||||
shutdown when threshold is exceeded. When not
|
||||
set, `nodeos` will shutdown.
|
||||
Used to indicate nodeos will not
|
||||
shutdown when threshold is exceeded.
|
||||
--resource-monitor-warning-interval arg (=30)
|
||||
Number of monitor intervals between which a
|
||||
warning is displayed. For example, if
|
||||
`resource-monitor-warning-interval` is to 10
|
||||
and `resource-monitor-interval-seconds` is 2,
|
||||
a warning will be displayed every 20 seconds,
|
||||
even though the space usage is checked every
|
||||
2 seconds. This is used to throttle the
|
||||
number of warnings in the `nodeos` log file.
|
||||
Should be between 1 and 450.
|
||||
Number of resource monitor intervals
|
||||
between two consecutive warnings when
|
||||
the threshold is hit. Should be between
|
||||
1 and 450
|
||||
```
|
||||
|
||||
## Plugin Dependencies
|
||||
|
||||
@@ -31,19 +31,21 @@ These can be specified from both the `nodeos` command-line or the `config.ini` f
|
||||
|
||||
```console
|
||||
Config Options for eosio::state_history_plugin:
|
||||
|
||||
--state-history-dir arg (="state-history")
|
||||
the location of the state-history
|
||||
the location of the state-history
|
||||
directory (absolute path or relative to
|
||||
application data dir)
|
||||
--trace-history enable trace history
|
||||
--chain-state-history enable chain state history
|
||||
--state-history-endpoint arg (=127.0.0.1:8080)
|
||||
the endpoint upon which to listen for
|
||||
incoming connections. Caution: only
|
||||
expose this port to your internal
|
||||
the endpoint upon which to listen for
|
||||
incoming connections. Caution: only
|
||||
expose this port to your internal
|
||||
network.
|
||||
--trace-history-debug-mode enable debug mode for trace history
|
||||
--state-history-log-retain-blocks arg if set, periodically prune the state
|
||||
history files to store only configured
|
||||
number of most recent blocks
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
@@ -64,24 +64,3 @@ Sample `logging.json`:
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Expected Output of Log Levels
|
||||
|
||||
* `error` - Log output that likely requires operator intervention.
|
||||
- Error level logging should be reserved for conditions that are completely unexpected or otherwise need human intervention.
|
||||
- Also used to indicate software errors such as: impossible values for an `enum`, out of bounds array access, null pointers, or other conditions that likely will throw an exception.
|
||||
- *Note*: Currently, there are numerous `error` level logging that likely should be `warn` as they do not require human intervention. The `net_plugin_impl`, for example, has a number of `error` level logs for bad network connections. This is handled and processed correctly. These should be changed to `warn` or `info`.
|
||||
* `warn` - Log output indicating unexpected but recoverable errors.
|
||||
- Although, `warn` level typically does not require human intervention, repeated output of `warn` level logs might indicate actions needed by an operator.
|
||||
- `warn` should not be used simply for conveying information. A `warn` level log is something to take notice of, but not necessarily be concerned about.
|
||||
* `info` (default) - Log output that provides useful information to an operator.
|
||||
- Can be just progress indication or other useful data to a user. Care is taken not to create excessive log output with `info` level logging. For example, no `info` level logging should be produced for every transaction.
|
||||
- For progress indication, some multiple of transactions should be processed between each log output; typically, every 1000 transactions.
|
||||
* `debug` - Useful log output for when non-default logging is enabled.
|
||||
- Answers the question: is this useful information for a user that is monitoring the log output. Care should be taken not to create excessive log output; similar to `info` level logging.
|
||||
- Enabling `debug` level logging should provide greater insight into behavior without overwhelming the output with log entries.
|
||||
- `debug` level should not be used for *trace* level logging; to that end, use `all` (see below).
|
||||
- Like `info`, no `debug` level logging should be produced for every transaction. There are specific transaction level loggers dedicated to transaction level logging: `transaction`, `transaction_trace_failure`, `transaction_trace_success`, `transaction_failure_tracing`, `transaction_success_tracing`.
|
||||
* `all` (trace) - For logging that would be overwhelming if `debug` level logging were used.
|
||||
- Can be used for trace level logging. Only used in a few places and not completely supported.
|
||||
- *Note*: In the future a different logging library may provide better trace level logging support. The current logging framework is not performant enough to enable excess trace level output.
|
||||
|
||||
@@ -4,10 +4,15 @@ set(APPBASE_INSTALL_COMPONENT "dev")
|
||||
set(SOFTFLOAT_INSTALL_COMPONENT "dev")
|
||||
set(EOSVM_INSTALL_COMPONENT "dev")
|
||||
|
||||
add_subdirectory( libfc )
|
||||
add_subdirectory( fc )
|
||||
add_subdirectory( builtins )
|
||||
|
||||
# Suppress warnings on 3rdParty Library
|
||||
add_definitions( -w )
|
||||
add_subdirectory( softfloat )
|
||||
add_subdirectory( wasm-jit )
|
||||
remove_definitions( -w )
|
||||
|
||||
add_subdirectory( chainbase )
|
||||
set(APPBASE_ENABLE_AUTO_VERSION OFF CACHE BOOL "enable automatic discovery of version via 'git describe'")
|
||||
add_subdirectory( appbase )
|
||||
@@ -15,7 +20,6 @@ add_subdirectory( chain )
|
||||
add_subdirectory( testing )
|
||||
add_subdirectory( version )
|
||||
add_subdirectory( state_history )
|
||||
add_subdirectory( cli11 )
|
||||
|
||||
set(USE_EXISTING_SOFTFLOAT ON CACHE BOOL "use pre-exisiting softfloat lib")
|
||||
set(ENABLE_TOOLS OFF CACHE BOOL "Build tools")
|
||||
@@ -27,12 +31,6 @@ if(eos-vm IN_LIST EOSIO_WASM_RUNTIMES OR eos-vm-jit IN_LIST EOSIO_WASM_RUNTIMES)
|
||||
add_subdirectory( eos-vm )
|
||||
endif()
|
||||
|
||||
#yubihsm's openssl discovery is via pkg-config instead of find_package. Help it out on macOS otherwise openssl's pkgconfig
|
||||
# files may not be found down in the /opt/homebrew/opt directory
|
||||
if(APPLE)
|
||||
get_filename_component(OPENSSL_LIB_PATH "${OPENSSL_CRYPTO_LIBRARY}" DIRECTORY)
|
||||
set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:${OPENSSL_LIB_PATH}/pkgconfig")
|
||||
endif()
|
||||
set(ENABLE_STATIC ON)
|
||||
set(CMAKE_MACOSX_RPATH OFF)
|
||||
set(BUILD_ONLY_LIB ON CACHE BOOL "Library only build")
|
||||
|
||||
+1
-1
Submodule libraries/appbase updated: 78062207ea...356a489123
@@ -72,9 +72,6 @@ set(CHAIN_WEBASSEMBLY_SOURCES
|
||||
webassembly/transaction.cpp
|
||||
)
|
||||
|
||||
add_library(eosio_rapidjson INTERFACE)
|
||||
target_include_directories(eosio_rapidjson INTERFACE ../rapidjson/include)
|
||||
|
||||
## SORT .cpp by most likely to change / break compile
|
||||
add_library( eosio_chain
|
||||
merkle.cpp
|
||||
@@ -128,7 +125,7 @@ add_library( eosio_chain
|
||||
${HEADERS}
|
||||
)
|
||||
|
||||
target_link_libraries( eosio_chain PUBLIC fc chainbase eosio_rapidjson Logging IR WAST WASM Runtime
|
||||
target_link_libraries( eosio_chain PUBLIC fc chainbase Logging IR WAST WASM Runtime
|
||||
softfloat builtins ${CHAIN_EOSVM_LIBRARIES} ${LLVM_LIBS} ${CHAIN_RT_LINKAGE}
|
||||
)
|
||||
target_include_directories( eosio_chain
|
||||
@@ -165,3 +162,6 @@ install( DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/eosio/chain/
|
||||
FILES_MATCHING PATTERN "*.hpp" PATTERN "*.h" EXCLUDE
|
||||
)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/include/eosio/chain/core_symbol.hpp DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR}/eosio/chain COMPONENT dev EXCLUDE_FROM_ALL)
|
||||
#if(MSVC)
|
||||
# set_source_files_properties( db_init.cpp db_block.cpp database.cpp block_log.cpp PROPERTIES COMPILE_FLAGS "/bigobj" )
|
||||
#endif(MSVC)
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace eosio { namespace chain {
|
||||
|
||||
abi_serializer::abi_serializer( const abi_def& abi, const fc::microseconds& max_serialization_time) {
|
||||
configure_built_in_types();
|
||||
set_abi(abi, create_yield_function(max_serialization_time));
|
||||
set_abi(abi, max_serialization_time);
|
||||
}
|
||||
|
||||
void abi_serializer::add_specialized_unpack_pack( const string& name,
|
||||
@@ -209,19 +209,6 @@ namespace eosio { namespace chain {
|
||||
return ends_with(type, "[]");
|
||||
}
|
||||
|
||||
bool abi_serializer::is_szarray(const string_view& type)const {
|
||||
auto pos1 = type.find_last_of('[');
|
||||
auto pos2 = type.find_last_of(']');
|
||||
if(pos1 == string_view::npos || pos2 == string_view::npos) return false;
|
||||
auto pos = pos1 + 1;
|
||||
if(pos == pos2) return false;
|
||||
while(pos < pos2) {
|
||||
if( ! (type[pos] >= '0' && type[pos] <= '9') ) return false;
|
||||
++pos;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool abi_serializer::is_optional(const string_view& type)const {
|
||||
return ends_with(type, "?");
|
||||
}
|
||||
@@ -238,8 +225,6 @@ namespace eosio { namespace chain {
|
||||
std::string_view abi_serializer::fundamental_type(const std::string_view& type)const {
|
||||
if( is_array(type) ) {
|
||||
return type.substr(0, type.size()-2);
|
||||
} else if (is_szarray (type) ){
|
||||
return type.substr(0, type.find_last_of('['));
|
||||
} else if ( is_optional(type) ) {
|
||||
return type.substr(0, type.size()-1);
|
||||
} else {
|
||||
@@ -410,8 +395,10 @@ namespace eosio { namespace chain {
|
||||
for( decltype(size.value) i = 0; i < size; ++i ) {
|
||||
ctx.set_array_index_of_path_back(i);
|
||||
auto v = _binary_to_variant(ftype, stream, ctx);
|
||||
// The exception below is commented out to allow array of optional as input data
|
||||
//EOS_ASSERT( !v.is_null(), unpack_exception, "Invalid packed array '${p}'", ("p", ctx.get_path_string()) );
|
||||
// QUESTION: Is it actually desired behavior to require the returned variant to not be null?
|
||||
// This would disallow arrays of optionals in general (though if all optionals in the array were present it would be allowed).
|
||||
// Is there any scenario in which the returned variant would be null other than in the case of an empty optional?
|
||||
EOS_ASSERT( !v.is_null(), unpack_exception, "Invalid packed array '${p}'", ("p", ctx.get_path_string()) );
|
||||
vars.emplace_back(std::move(v));
|
||||
}
|
||||
// QUESTION: Why would the assert below ever fail?
|
||||
|
||||
@@ -71,53 +71,51 @@ void apply_context::exec_one()
|
||||
try {
|
||||
action_return_value.clear();
|
||||
receiver_account = &db.get<account_metadata_object,by_name>( receiver );
|
||||
if( !(context_free && control.skip_trx_checks()) ) {
|
||||
privileged = receiver_account->is_privileged();
|
||||
auto native = control.find_apply_handler( receiver, act->account, act->name );
|
||||
if( native ) {
|
||||
if( trx_context.enforce_whiteblacklist && control.is_producing_block() ) {
|
||||
control.check_contract_list( receiver );
|
||||
control.check_action_list( act->account, act->name );
|
||||
}
|
||||
(*native)( *this );
|
||||
privileged = receiver_account->is_privileged();
|
||||
auto native = control.find_apply_handler( receiver, act->account, act->name );
|
||||
if( native ) {
|
||||
if( trx_context.enforce_whiteblacklist && control.is_producing_block() ) {
|
||||
control.check_contract_list( receiver );
|
||||
control.check_action_list( act->account, act->name );
|
||||
}
|
||||
(*native)( *this );
|
||||
}
|
||||
|
||||
if( ( receiver_account->code_hash != digest_type() ) &&
|
||||
( !( act->account == config::system_account_name
|
||||
&& act->name == "setcode"_n
|
||||
&& receiver == config::system_account_name )
|
||||
|| control.is_builtin_activated( builtin_protocol_feature_t::forward_setcode )
|
||||
)
|
||||
) {
|
||||
if( trx_context.enforce_whiteblacklist && control.is_producing_block() ) {
|
||||
control.check_contract_list( receiver );
|
||||
control.check_action_list( act->account, act->name );
|
||||
}
|
||||
try {
|
||||
control.get_wasm_interface().apply( receiver_account->code_hash, receiver_account->vm_type, receiver_account->vm_version, *this );
|
||||
} catch( const wasm_exit& ) {}
|
||||
if( ( receiver_account->code_hash != digest_type() ) &&
|
||||
( !( act->account == config::system_account_name
|
||||
&& act->name == "setcode"_n
|
||||
&& receiver == config::system_account_name )
|
||||
|| control.is_builtin_activated( builtin_protocol_feature_t::forward_setcode )
|
||||
)
|
||||
) {
|
||||
if( trx_context.enforce_whiteblacklist && control.is_producing_block() ) {
|
||||
control.check_contract_list( receiver );
|
||||
control.check_action_list( act->account, act->name );
|
||||
}
|
||||
try {
|
||||
control.get_wasm_interface().apply( receiver_account->code_hash, receiver_account->vm_type, receiver_account->vm_version, *this );
|
||||
} catch( const wasm_exit& ) {}
|
||||
}
|
||||
|
||||
if( !privileged && control.is_builtin_activated( builtin_protocol_feature_t::ram_restrictions ) ) {
|
||||
const size_t checktime_interval = 10;
|
||||
size_t counter = 0;
|
||||
bool not_in_notify_context = (receiver == act->account);
|
||||
const auto end = _account_ram_deltas.end();
|
||||
for( auto itr = _account_ram_deltas.begin(); itr != end; ++itr, ++counter ) {
|
||||
if( counter == checktime_interval ) {
|
||||
trx_context.checktime();
|
||||
counter = 0;
|
||||
}
|
||||
if( itr->delta > 0 && itr->account != receiver ) {
|
||||
EOS_ASSERT( not_in_notify_context, unauthorized_ram_usage_increase,
|
||||
"unprivileged contract cannot increase RAM usage of another account within a notify context: ${account}",
|
||||
("account", itr->account)
|
||||
);
|
||||
EOS_ASSERT( has_authorization( itr->account ), unauthorized_ram_usage_increase,
|
||||
"unprivileged contract cannot increase RAM usage of another account that has not authorized the action: ${account}",
|
||||
("account", itr->account)
|
||||
);
|
||||
}
|
||||
if( !privileged && control.is_builtin_activated( builtin_protocol_feature_t::ram_restrictions ) ) {
|
||||
const size_t checktime_interval = 10;
|
||||
size_t counter = 0;
|
||||
bool not_in_notify_context = (receiver == act->account);
|
||||
const auto end = _account_ram_deltas.end();
|
||||
for( auto itr = _account_ram_deltas.begin(); itr != end; ++itr, ++counter ) {
|
||||
if( counter == checktime_interval ) {
|
||||
trx_context.checktime();
|
||||
counter = 0;
|
||||
}
|
||||
if( itr->delta > 0 && itr->account != receiver ) {
|
||||
EOS_ASSERT( not_in_notify_context, unauthorized_ram_usage_increase,
|
||||
"unprivileged contract cannot increase RAM usage of another account within a notify context: ${account}",
|
||||
("account", itr->account)
|
||||
);
|
||||
EOS_ASSERT( has_authorization( itr->account ), unauthorized_ram_usage_increase,
|
||||
"unprivileged contract cannot increase RAM usage of another account that has not authorized the action: ${account}",
|
||||
("account", itr->account)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+63
-149
@@ -1,5 +1,6 @@
|
||||
#include <eosio/chain/block_log.hpp>
|
||||
#include <eosio/chain/exceptions.hpp>
|
||||
#include <fstream>
|
||||
#include <fc/bitutil.hpp>
|
||||
#include <fc/io/cfile.hpp>
|
||||
#include <fc/io/raw.hpp>
|
||||
@@ -48,21 +49,14 @@ namespace eosio { namespace chain {
|
||||
uint32_t first_block_num = 0; //the first number available to read
|
||||
uint32_t index_first_block_num = 0; //the first number in index & the log had it not been pruned
|
||||
std::optional<block_log_prune_config> prune_config;
|
||||
bool not_generate_block_log = false;
|
||||
|
||||
explicit block_log_impl(std::optional<block_log_prune_config> prune_conf) :
|
||||
block_log_impl(std::optional<block_log_prune_config> prune_conf) :
|
||||
prune_config(prune_conf) {
|
||||
if(prune_config) {
|
||||
if (prune_config->prune_blocks == 0 ) {
|
||||
// not to generate blocks.log
|
||||
// disable prune log handling by resetting prune_config
|
||||
prune_config.reset();
|
||||
not_generate_block_log = true;
|
||||
} else {
|
||||
EOS_ASSERT(__builtin_popcount(prune_config->prune_threshold) == 1, block_log_exception, "block log prune threshold must be power of 2");
|
||||
//switch this over to the mask that will be used
|
||||
prune_config->prune_threshold = ~(prune_config->prune_threshold-1);
|
||||
}
|
||||
EOS_ASSERT(prune_config->prune_blocks, block_log_exception, "block log prune configuration requires at least one block");
|
||||
EOS_ASSERT(__builtin_popcount(prune_config->prune_threshold) == 1, block_log_exception, "block log prune threshold must be power of 2");
|
||||
//switch this over to the mask that will be used
|
||||
prune_config->prune_threshold = ~(prune_config->prune_threshold-1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +65,6 @@ namespace eosio { namespace chain {
|
||||
reopen();
|
||||
}
|
||||
}
|
||||
|
||||
void reopen();
|
||||
|
||||
//close() is called all over the place. Let's make this an explict call to ensure it only is called when
|
||||
@@ -106,17 +99,13 @@ namespace eosio { namespace chain {
|
||||
template<typename T>
|
||||
void reset( const T& t, const signed_block_ptr& genesis_block, uint32_t first_block_num );
|
||||
|
||||
void remove();
|
||||
|
||||
void write( const genesis_state& gs );
|
||||
|
||||
void write( const chain_id_type& chain_id );
|
||||
|
||||
void flush();
|
||||
|
||||
void append(const signed_block_ptr& b, const block_id_type& id, const std::vector<char>& packed_block);
|
||||
|
||||
void update_head(const signed_block_ptr& b, const std::optional<block_id_type>& id={});
|
||||
void append(const signed_block_ptr& b);
|
||||
|
||||
void prune(const fc::log_level& loglevel);
|
||||
|
||||
@@ -302,7 +291,12 @@ namespace eosio { namespace chain {
|
||||
}
|
||||
my->index_first_block_num = my->first_block_num;
|
||||
|
||||
my->update_head(read_head());
|
||||
my->head = read_head();
|
||||
if( my->head ) {
|
||||
my->head_id = my->head->calculate_id();
|
||||
} else {
|
||||
my->head_id = {};
|
||||
}
|
||||
|
||||
my->block_file.seek_end(0);
|
||||
if(is_currently_pruned && my->head) {
|
||||
@@ -361,23 +355,14 @@ namespace eosio { namespace chain {
|
||||
}
|
||||
}
|
||||
|
||||
void block_log::append(const signed_block_ptr& b, const block_id_type& id) {
|
||||
my->append(b, id, fc::raw::pack(*b));
|
||||
void block_log::append(const signed_block_ptr& b) {
|
||||
my->append(b);
|
||||
}
|
||||
|
||||
void block_log::append(const signed_block_ptr& b, const block_id_type& id, const std::vector<char>& packed_block) {
|
||||
my->append(b, id, packed_block);
|
||||
}
|
||||
|
||||
void detail::block_log_impl::append(const signed_block_ptr& b, const block_id_type& id, const std::vector<char>& packed_block) {
|
||||
void detail::block_log_impl::append(const signed_block_ptr& b) {
|
||||
try {
|
||||
EOS_ASSERT( genesis_written_to_block_log, block_log_append_fail, "Cannot append to block log until the genesis is first written" );
|
||||
|
||||
if (not_generate_block_log) {
|
||||
update_head(b, id);
|
||||
return;
|
||||
}
|
||||
|
||||
check_open_files();
|
||||
|
||||
block_file.seek_end(0);
|
||||
@@ -392,12 +377,13 @@ namespace eosio { namespace chain {
|
||||
"Append to index file occuring at wrong position.",
|
||||
("position", (uint64_t) index_file.tellp())
|
||||
("expected", (b->block_num() - index_first_block_num) * sizeof(uint64_t)));
|
||||
block_file.write(packed_block.data(), packed_block.size());
|
||||
auto data = fc::raw::pack(*b);
|
||||
block_file.write(data.data(), data.size());
|
||||
block_file.write((char*)&pos, sizeof(pos));
|
||||
const uint64_t end = block_file.tellp();
|
||||
index_file.write((char*)&pos, sizeof(pos));
|
||||
|
||||
update_head(b, id);
|
||||
head = b;
|
||||
head_id = b->calculate_id();
|
||||
|
||||
if(prune_config) {
|
||||
if((pos&prune_config->prune_threshold) != (end&prune_config->prune_threshold))
|
||||
@@ -412,19 +398,6 @@ namespace eosio { namespace chain {
|
||||
FC_LOG_AND_RETHROW()
|
||||
}
|
||||
|
||||
void detail::block_log_impl::update_head(const signed_block_ptr& b, const std::optional<block_id_type>& id) {
|
||||
head = b;
|
||||
if (id) {
|
||||
head_id = *id;
|
||||
} else {
|
||||
if (head) {
|
||||
head_id = b->calculate_id();
|
||||
} else {
|
||||
head_id = {};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void detail::block_log_impl::prune(const fc::log_level& loglevel) {
|
||||
if(!head)
|
||||
return;
|
||||
@@ -451,9 +424,6 @@ namespace eosio { namespace chain {
|
||||
}
|
||||
|
||||
void block_log::flush() {
|
||||
if (my->not_generate_block_log) {
|
||||
return;
|
||||
}
|
||||
my->flush();
|
||||
}
|
||||
|
||||
@@ -598,7 +568,7 @@ namespace eosio { namespace chain {
|
||||
block_file.write((char*)&totem, sizeof(totem));
|
||||
|
||||
if (first_block) {
|
||||
append(first_block, first_block->calculate_id(), fc::raw::pack(*first_block));
|
||||
append(first_block);
|
||||
} else {
|
||||
head.reset();
|
||||
head_id = {};
|
||||
@@ -621,30 +591,15 @@ namespace eosio { namespace chain {
|
||||
}
|
||||
|
||||
void block_log::reset( const genesis_state& gs, const signed_block_ptr& first_block ) {
|
||||
// At startup, OK to be called in no blocks.log mode from controller.cpp
|
||||
my->reset(gs, first_block, 1);
|
||||
}
|
||||
|
||||
void block_log::reset( const chain_id_type& chain_id, uint32_t first_block_num ) {
|
||||
// At startup, OK to be called in no blocks.log mode from controller.cpp
|
||||
EOS_ASSERT( first_block_num > 1, block_log_exception,
|
||||
"Block log version ${ver} needs to be created with a genesis state if starting from block number 1." );
|
||||
my->reset(chain_id, signed_block_ptr(), first_block_num);
|
||||
}
|
||||
|
||||
void detail::block_log_impl::remove() {
|
||||
close();
|
||||
|
||||
fc::remove( block_file.get_file_path() );
|
||||
fc::remove( index_file.get_file_path() );
|
||||
|
||||
ilog("block log ${l}, block index ${i} removed", ("l", block_file.get_file_path()) ("i", index_file.get_file_path()));
|
||||
}
|
||||
|
||||
void block_log::remove() {
|
||||
my->remove();
|
||||
}
|
||||
|
||||
void detail::block_log_impl::write( const genesis_state& gs ) {
|
||||
auto data = fc::raw::pack(gs);
|
||||
block_file.write(data.data(), data.size());
|
||||
@@ -655,10 +610,6 @@ namespace eosio { namespace chain {
|
||||
}
|
||||
|
||||
signed_block_ptr block_log::read_block(uint64_t pos)const {
|
||||
if (my->not_generate_block_log) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
my->check_open_files();
|
||||
|
||||
my->block_file.seek(pos);
|
||||
@@ -669,10 +620,6 @@ namespace eosio { namespace chain {
|
||||
}
|
||||
|
||||
void block_log::read_block_header(block_header& bh, uint64_t pos)const {
|
||||
if (my->not_generate_block_log) {
|
||||
return;
|
||||
}
|
||||
|
||||
my->check_open_files();
|
||||
|
||||
my->block_file.seek(pos);
|
||||
@@ -683,12 +630,6 @@ namespace eosio { namespace chain {
|
||||
signed_block_ptr block_log::read_block_by_num(uint32_t block_num)const {
|
||||
try {
|
||||
signed_block_ptr b;
|
||||
|
||||
if (my->not_generate_block_log) {
|
||||
// No blocks exist. Avoid cascading failures if going further.
|
||||
return b;
|
||||
}
|
||||
|
||||
uint64_t pos = get_block_pos(block_num);
|
||||
if (pos != npos) {
|
||||
b = read_block(pos);
|
||||
@@ -701,9 +642,6 @@ namespace eosio { namespace chain {
|
||||
|
||||
block_id_type block_log::read_block_id_by_num(uint32_t block_num)const {
|
||||
try {
|
||||
if (my->not_generate_block_log) {
|
||||
return {};
|
||||
}
|
||||
uint64_t pos = get_block_pos(block_num);
|
||||
if (pos != npos) {
|
||||
block_header bh;
|
||||
@@ -727,17 +665,10 @@ namespace eosio { namespace chain {
|
||||
}
|
||||
|
||||
uint64_t block_log::get_block_pos(uint32_t block_num) const {
|
||||
if (my->not_generate_block_log) {
|
||||
return block_log::npos;
|
||||
}
|
||||
return my->get_block_pos(block_num);
|
||||
}
|
||||
|
||||
signed_block_ptr block_log::read_head()const {
|
||||
if (my->not_generate_block_log) {
|
||||
return {};
|
||||
}
|
||||
|
||||
my->check_open_files();
|
||||
|
||||
uint64_t pos;
|
||||
@@ -777,11 +708,6 @@ namespace eosio { namespace chain {
|
||||
}
|
||||
|
||||
void block_log::construct_index() {
|
||||
if (my->not_generate_block_log) {
|
||||
ilog("Not need to construct index in no blocks.log mode (block-log-retain-blocks=0)");
|
||||
return;
|
||||
}
|
||||
|
||||
ilog("Reconstructing Block Log Index...");
|
||||
my->close();
|
||||
|
||||
@@ -1261,29 +1187,31 @@ namespace eosio { namespace chain {
|
||||
}
|
||||
}
|
||||
|
||||
bool block_log::extract_block_range(const fc::path& block_dir, const fc::path&output_dir, block_num_type& start, block_num_type& end, bool rename_input) {
|
||||
EOS_ASSERT( block_dir != output_dir, block_log_exception, "block_dir and output_dir need to be different directories" );
|
||||
bool block_log::trim_blocklog_front(const fc::path& block_dir, const fc::path& temp_dir, uint32_t truncate_at_block) {
|
||||
using namespace std;
|
||||
EOS_ASSERT( block_dir != temp_dir, block_log_exception, "block_dir and temp_dir need to be different directories" );
|
||||
ilog("In directory ${dir} will trim all blocks before block ${n} from blocks.log and blocks.index.",
|
||||
("dir", block_dir.generic_string())("n", truncate_at_block));
|
||||
trim_data original_block_log(block_dir);
|
||||
if(start < original_block_log.first_block) {
|
||||
dlog("Requested start block of ${start} is less than the first available block ${n}; adjusting to ${n}", ("start", start)("n", original_block_log.first_block));
|
||||
start = original_block_log.first_block;
|
||||
if (truncate_at_block <= original_block_log.first_block) {
|
||||
ilog("There are no blocks before block ${n} so do nothing.", ("n", truncate_at_block));
|
||||
return false;
|
||||
}
|
||||
if(end > original_block_log.last_block) {
|
||||
dlog("Requested end block of ${end} is greater than the last available block ${n}; adjusting to ${n}", ("end", end)("n", original_block_log.last_block));
|
||||
end = original_block_log.last_block;
|
||||
if (truncate_at_block > original_block_log.last_block) {
|
||||
ilog("All blocks are before block ${n} so do nothing (trim front would delete entire blocks.log).", ("n", truncate_at_block));
|
||||
return false;
|
||||
}
|
||||
ilog("In directory ${output} will create new block log with range ${start}-${end}",
|
||||
("output", output_dir.generic_string())("start", start)("end", end));
|
||||
|
||||
// ****** create the new block log file and write out the header for the file
|
||||
fc::create_directories(output_dir);
|
||||
fc::path new_block_filename = output_dir / "blocks.log";
|
||||
fc::create_directories(temp_dir);
|
||||
fc::path new_block_filename = temp_dir / "blocks.log";
|
||||
if (fc::remove(new_block_filename)) {
|
||||
ilog("Removing existing blocks.log file");
|
||||
ilog("Removing old blocks.out file");
|
||||
}
|
||||
fc::cfile new_block_file;
|
||||
new_block_file.set_file_path(new_block_filename);
|
||||
// need to open as write since the file doesn't already exist, then reopen
|
||||
// with read/write to allow writing the file in any order
|
||||
// need to open as append since the file doesn't already exist, then reopen without append to allow writing the
|
||||
// file in any order
|
||||
new_block_file.open( LOG_WRITE_C );
|
||||
new_block_file.close();
|
||||
new_block_file.open( LOG_RW_C );
|
||||
@@ -1293,49 +1221,37 @@ namespace eosio { namespace chain {
|
||||
uint32_t version = block_log::max_supported_version;
|
||||
new_block_file.seek(0);
|
||||
new_block_file.write((char*)&version, sizeof(version));
|
||||
new_block_file.write((char*)&start, sizeof(start));
|
||||
new_block_file.write((char*)&truncate_at_block, sizeof(truncate_at_block));
|
||||
|
||||
if (start > 1) {
|
||||
new_block_file << original_block_log.chain_id;
|
||||
} else {
|
||||
fc::raw::pack(new_block_file, original_block_log.gs);
|
||||
}
|
||||
new_block_file << original_block_log.chain_id;
|
||||
|
||||
// append a totem to indicate the division between blocks and header
|
||||
auto totem = block_log::npos;
|
||||
new_block_file.write((char*)&totem, sizeof(totem));
|
||||
// ****** end of new block log header
|
||||
|
||||
const auto new_block_file_first_block_pos = new_block_file.tellp();
|
||||
// ****** end of new block log header
|
||||
|
||||
// copy over remainder of block log to new block log
|
||||
auto buffer = std::make_unique<char[]>(detail::reverse_iterator::_buf_len);
|
||||
auto buffer = make_unique<char[]>(detail::reverse_iterator::_buf_len);
|
||||
char* buf = buffer.get();
|
||||
|
||||
// offset bytes to shift from old blocklog position to new blocklog position
|
||||
const uint64_t original_file_start_block_pos = original_block_log.block_pos(start);
|
||||
const uint64_t pos_delta = original_file_start_block_pos - new_block_file_first_block_pos;
|
||||
uint64_t original_file_end_block_pos;
|
||||
if (end == original_block_log.last_block) {
|
||||
auto status = fseek(original_block_log.blk_in, 0, SEEK_END);
|
||||
EOS_ASSERT( status == 0, block_log_exception, "blocks.log seek failed" );
|
||||
original_file_end_block_pos = ftell(original_block_log.blk_in);
|
||||
} else {
|
||||
original_file_end_block_pos = original_block_log.block_pos(end+1);
|
||||
auto status = fseek(original_block_log.blk_in, original_file_end_block_pos, SEEK_SET);
|
||||
EOS_ASSERT( status == 0, block_log_exception, "blocks.log seek failed" );
|
||||
}
|
||||
const uint64_t original_file_block_pos = original_block_log.block_pos(truncate_at_block);
|
||||
const uint64_t pos_delta = original_file_block_pos - new_block_file_first_block_pos;
|
||||
auto status = fseek(original_block_log.blk_in, 0, SEEK_END);
|
||||
EOS_ASSERT( status == 0, block_log_exception, "blocks.log seek failed" );
|
||||
|
||||
// all bytes to copy to the new blocklog
|
||||
const uint64_t to_write = original_file_end_block_pos - original_file_start_block_pos;
|
||||
// all blocks to copy to the new blocklog
|
||||
const uint64_t to_write = ftell(original_block_log.blk_in) - original_file_block_pos;
|
||||
const auto pos_size = sizeof(uint64_t);
|
||||
|
||||
// start with the last block's position stored at the end of the block
|
||||
const auto pos_size = sizeof(uint64_t);
|
||||
uint64_t original_pos = original_file_end_block_pos - pos_size;
|
||||
uint64_t original_pos = ftell(original_block_log.blk_in) - pos_size;
|
||||
|
||||
const auto num_blocks = end - start + 1;
|
||||
const auto num_blocks = original_block_log.last_block - truncate_at_block + 1;
|
||||
|
||||
fc::path new_index_filename = output_dir / "blocks.index";
|
||||
fc::path new_index_filename = temp_dir / "blocks.index";
|
||||
detail::index_writer index(new_index_filename, num_blocks);
|
||||
|
||||
uint64_t read_size = 0;
|
||||
@@ -1347,11 +1263,10 @@ namespace eosio { namespace chain {
|
||||
}
|
||||
|
||||
// read in the previous contiguous memory into the read buffer
|
||||
const auto start_of_blk_buffer_pos = original_file_start_block_pos + to_write_remaining - read_size;
|
||||
auto status = fseek(original_block_log.blk_in, start_of_blk_buffer_pos, SEEK_SET);
|
||||
EOS_ASSERT( status == 0, block_log_exception, "original blocks.log seek failed" );
|
||||
const auto start_of_blk_buffer_pos = original_file_block_pos + to_write_remaining - read_size;
|
||||
status = fseek(original_block_log.blk_in, start_of_blk_buffer_pos, SEEK_SET);
|
||||
const auto num_read = fread(buf, read_size, 1, original_block_log.blk_in);
|
||||
EOS_ASSERT( num_read == 1, block_log_exception, "original blocks.log read failed" );
|
||||
EOS_ASSERT( num_read == 1, block_log_exception, "blocks.log read failed" );
|
||||
|
||||
// walk this memory section to adjust block position to match the adjusted location
|
||||
// of the block start and store in the new index file
|
||||
@@ -1380,14 +1295,12 @@ namespace eosio { namespace chain {
|
||||
new_block_file.flush();
|
||||
new_block_file.close();
|
||||
|
||||
if (rename_input) {
|
||||
fc::path old_log = output_dir / "old.log";
|
||||
rename(original_block_log.block_file_name, old_log);
|
||||
rename(new_block_filename, original_block_log.block_file_name);
|
||||
fc::path old_ind = output_dir / "old.index";
|
||||
rename(original_block_log.index_file_name, old_ind);
|
||||
rename(new_index_filename, original_block_log.index_file_name);
|
||||
}
|
||||
fc::path old_log = temp_dir / "old.log";
|
||||
rename(original_block_log.block_file_name, old_log);
|
||||
rename(new_block_filename, original_block_log.block_file_name);
|
||||
fc::path old_ind = temp_dir / "old.index";
|
||||
rename(original_block_log.index_file_name, old_ind);
|
||||
rename(new_index_filename, original_block_log.index_file_name);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1422,6 +1335,7 @@ namespace eosio { namespace chain {
|
||||
EOS_ASSERT(size == 1, block_log_exception, "invalid format for file ${file}",
|
||||
("file", block_file_name.string()));
|
||||
if (block_log::contains_genesis_state(version, first_block)) {
|
||||
genesis_state gs;
|
||||
fc::raw::unpack(ds, gs);
|
||||
chain_id = gs.compute_chain_id();
|
||||
}
|
||||
@@ -1517,4 +1431,4 @@ namespace eosio { namespace chain {
|
||||
// used only for unit test to adjust the buffer length
|
||||
void block_log_set_buff_len(uint64_t len){
|
||||
eosio::chain::detail::reverse_iterator::_buf_len = len;
|
||||
}
|
||||
}
|
||||
@@ -88,7 +88,7 @@ namespace eosio { namespace chain {
|
||||
|
||||
block_state::block_state( pending_block_header_state&& cur,
|
||||
signed_block_ptr&& b,
|
||||
deque<transaction_metadata_ptr>&& trx_metas,
|
||||
vector<transaction_metadata_ptr>&& trx_metas,
|
||||
const protocol_feature_set& pfs,
|
||||
const std::function<void( block_timestamp_type,
|
||||
const flat_set<digest_type>&,
|
||||
|
||||
+129
-179
@@ -115,23 +115,22 @@ struct building_block {
|
||||
const vector<digest_type>& new_protocol_feature_activations )
|
||||
:_pending_block_header_state( prev.next( when, num_prev_blocks_to_confirm ) )
|
||||
,_new_protocol_feature_activations( new_protocol_feature_activations )
|
||||
,_trx_mroot_or_receipt_digests( digests_t{} )
|
||||
{}
|
||||
|
||||
pending_block_header_state _pending_block_header_state;
|
||||
std::optional<producer_authority_schedule> _new_pending_producer_schedule;
|
||||
vector<digest_type> _new_protocol_feature_activations;
|
||||
size_t _num_new_protocol_features_that_have_activated = 0;
|
||||
deque<transaction_metadata_ptr> _pending_trx_metas;
|
||||
deque<transaction_receipt> _pending_trx_receipts; // boost deque in 1.71 with 1024 elements performs better
|
||||
std::variant<checksum256_type, digests_t> _trx_mroot_or_receipt_digests;
|
||||
digests_t _action_receipt_digests;
|
||||
vector<transaction_metadata_ptr> _pending_trx_metas;
|
||||
vector<transaction_receipt> _pending_trx_receipts;
|
||||
vector<digest_type> _action_receipt_digests;
|
||||
std::optional<checksum256_type> _transaction_mroot;
|
||||
};
|
||||
|
||||
struct assembled_block {
|
||||
block_id_type _id;
|
||||
pending_block_header_state _pending_block_header_state;
|
||||
deque<transaction_metadata_ptr> _trx_metas;
|
||||
vector<transaction_metadata_ptr> _trx_metas;
|
||||
signed_block_ptr _unsigned_block;
|
||||
|
||||
// if the _unsigned_block pre-dates block-signing authorities this may be present.
|
||||
@@ -157,7 +156,6 @@ struct pending_state {
|
||||
block_stage_type _block_stage;
|
||||
controller::block_status _block_status = controller::block_status::incomplete;
|
||||
std::optional<block_id_type> _producer_block_id;
|
||||
controller::block_report _block_report{};
|
||||
|
||||
/** @pre _block_stage cannot hold completed_block alternative */
|
||||
const pending_block_header_state& get_pending_block_header_state()const {
|
||||
@@ -167,7 +165,17 @@ struct pending_state {
|
||||
return std::get<assembled_block>(_block_stage)._pending_block_header_state;
|
||||
}
|
||||
|
||||
deque<transaction_metadata_ptr> extract_trx_metas() {
|
||||
const vector<transaction_receipt>& get_trx_receipts()const {
|
||||
if( std::holds_alternative<building_block>(_block_stage) )
|
||||
return std::get<building_block>(_block_stage)._pending_trx_receipts;
|
||||
|
||||
if( std::holds_alternative<assembled_block>(_block_stage) )
|
||||
return std::get<assembled_block>(_block_stage)._unsigned_block->transactions;
|
||||
|
||||
return std::get<completed_block>(_block_stage)._block_state->block->transactions;
|
||||
}
|
||||
|
||||
vector<transaction_metadata_ptr> extract_trx_metas() {
|
||||
if( std::holds_alternative<building_block>(_block_stage) )
|
||||
return std::move( std::get<building_block>(_block_stage)._pending_trx_metas );
|
||||
|
||||
@@ -239,7 +247,6 @@ struct controller_impl {
|
||||
named_thread_pool thread_pool;
|
||||
platform_timer timer;
|
||||
deep_mind_handler* deep_mind_logger = nullptr;
|
||||
bool okay_to_print_integrity_hash_on_stop = false;
|
||||
#if defined(EOSIO_EOS_VM_RUNTIME_ENABLED) || defined(EOSIO_EOS_VM_JIT_RUNTIME_ENABLED)
|
||||
vm::wasm_allocator wasm_alloc;
|
||||
#endif
|
||||
@@ -404,20 +411,12 @@ struct controller_impl {
|
||||
if( fork_head->dpos_irreversible_blocknum <= lib_num )
|
||||
return;
|
||||
|
||||
auto branch = fork_db.fetch_branch( fork_head->id, fork_head->dpos_irreversible_blocknum );
|
||||
const auto branch = fork_db.fetch_branch( fork_head->id, fork_head->dpos_irreversible_blocknum );
|
||||
try {
|
||||
|
||||
std::vector<std::future<std::vector<char>>> v;
|
||||
v.reserve( branch.size() );
|
||||
for( auto bitr = branch.rbegin(); bitr != branch.rend(); ++bitr ) {
|
||||
v.emplace_back( async_thread_pool( thread_pool.get_executor(), [b=(*bitr)->block]() { return fc::raw::pack(*b); } ) );
|
||||
}
|
||||
auto it = v.begin();
|
||||
|
||||
for( auto bitr = branch.rbegin(); bitr != branch.rend(); ++bitr ) {
|
||||
if( read_mode == db_read_mode::IRREVERSIBLE ) {
|
||||
controller::block_report br;
|
||||
apply_block( br, *bitr, controller::block_status::complete, trx_meta_cache_lookup{} );
|
||||
apply_block( *bitr, controller::block_status::complete, trx_meta_cache_lookup{} );
|
||||
head = (*bitr);
|
||||
fork_db.mark_valid( head );
|
||||
}
|
||||
@@ -426,8 +425,7 @@ struct controller_impl {
|
||||
|
||||
// blog.append could fail due to failures like running out of space.
|
||||
// Do it before commit so that in case it throws, DB can be rolled back.
|
||||
blog.append( (*bitr)->block, (*bitr)->id, it->get() );
|
||||
++it;
|
||||
blog.append( (*bitr)->block );
|
||||
|
||||
db.commit( (*bitr)->block_num );
|
||||
root_id = (*bitr)->id;
|
||||
@@ -442,12 +440,8 @@ struct controller_impl {
|
||||
//db.commit( fork_head->dpos_irreversible_blocknum ); // redundant
|
||||
|
||||
if( root_id != fork_db.root()->id ) {
|
||||
branch.emplace_back(fork_db.root());
|
||||
fork_db.advance_root( root_id );
|
||||
}
|
||||
|
||||
// delete branch in thread pool
|
||||
boost::asio::post( thread_pool.get_executor(), [branch{std::move(branch)}]() {} );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -574,6 +568,8 @@ struct controller_impl {
|
||||
"Snapshot is invalid." );
|
||||
blog.reset( chain_id, lib_num + 1 );
|
||||
}
|
||||
const auto hash = calculate_integrity_hash();
|
||||
ilog( "database initialized with hash: ${hash}", ("hash", hash) );
|
||||
|
||||
init(check_shutdown);
|
||||
ilog( "Finished initialization from snapshot" );
|
||||
@@ -582,9 +578,6 @@ struct controller_impl {
|
||||
shutdown();
|
||||
}
|
||||
|
||||
if (conf.prune_config && conf.prune_config->prune_blocks == 0) {
|
||||
blog.remove();
|
||||
}
|
||||
}
|
||||
|
||||
void startup(std::function<void()> shutdown, std::function<bool()> check_shutdown, const genesis_state& genesis) {
|
||||
@@ -618,10 +611,6 @@ struct controller_impl {
|
||||
blog.reset( genesis, head->block );
|
||||
}
|
||||
init(check_shutdown);
|
||||
|
||||
if (conf.prune_config && conf.prune_config->prune_blocks == 0) {
|
||||
blog.remove();
|
||||
}
|
||||
}
|
||||
|
||||
void startup(std::function<void()> shutdown, std::function<bool()> check_shutdown) {
|
||||
@@ -652,10 +641,6 @@ struct controller_impl {
|
||||
head = fork_db.head();
|
||||
|
||||
init(check_shutdown);
|
||||
|
||||
if (conf.prune_config && conf.prune_config->prune_blocks == 0) {
|
||||
blog.remove();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -710,10 +695,6 @@ struct controller_impl {
|
||||
dm_logger->on_startup(db, head->block_num);
|
||||
}
|
||||
|
||||
if( conf.integrity_hash_on_start )
|
||||
ilog( "chain database started with hash: ${hash}", ("hash", calculate_integrity_hash()) );
|
||||
okay_to_print_integrity_hash_on_stop = true;
|
||||
|
||||
replay( check_shutdown ); // replay any irreversible and reversible blocks ahead of current head
|
||||
|
||||
if( check_shutdown() ) return;
|
||||
@@ -733,8 +714,7 @@ struct controller_impl {
|
||||
pending_head = fork_db.pending_head()
|
||||
) {
|
||||
wlog( "applying branch from fork database ending with block: ${id}", ("id", pending_head->id) );
|
||||
controller::block_report br;
|
||||
maybe_switch_forks( br, pending_head, controller::block_status::complete, forked_branch_callback{}, trx_meta_cache_lookup{} );
|
||||
maybe_switch_forks( pending_head, controller::block_status::complete, forked_branch_callback{}, trx_meta_cache_lookup{} );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -742,9 +722,6 @@ struct controller_impl {
|
||||
~controller_impl() {
|
||||
thread_pool.stop();
|
||||
pending.reset();
|
||||
//only log this not just if configured to, but also if initialization made it to the point we'd log the startup too
|
||||
if(okay_to_print_integrity_hash_on_stop && conf.integrity_hash_on_stop)
|
||||
ilog( "chain database stopped with hash: ${hash}", ("hash", calculate_integrity_hash()) );
|
||||
}
|
||||
|
||||
void add_indices() {
|
||||
@@ -1102,22 +1079,18 @@ struct controller_impl {
|
||||
// The returned scoped_exit should not exceed the lifetime of the pending which existed when make_block_restore_point was called.
|
||||
fc::scoped_exit<std::function<void()>> make_block_restore_point() {
|
||||
auto& bb = std::get<building_block>(pending->_block_stage);
|
||||
auto orig_trx_receipts_size = bb._pending_trx_receipts.size();
|
||||
auto orig_trx_metas_size = bb._pending_trx_metas.size();
|
||||
auto orig_trx_receipt_digests_size = std::holds_alternative<digests_t>(bb._trx_mroot_or_receipt_digests) ?
|
||||
std::get<digests_t>(bb._trx_mroot_or_receipt_digests).size() : 0;
|
||||
auto orig_block_transactions_size = bb._pending_trx_receipts.size();
|
||||
auto orig_state_transactions_size = bb._pending_trx_metas.size();
|
||||
auto orig_action_receipt_digests_size = bb._action_receipt_digests.size();
|
||||
|
||||
std::function<void()> callback = [this,
|
||||
orig_trx_receipts_size,
|
||||
orig_trx_metas_size,
|
||||
orig_trx_receipt_digests_size,
|
||||
orig_action_receipt_digests_size]()
|
||||
orig_block_transactions_size,
|
||||
orig_state_transactions_size,
|
||||
orig_action_receipt_digests_size]()
|
||||
{
|
||||
auto& bb = std::get<building_block>(pending->_block_stage);
|
||||
bb._pending_trx_receipts.resize(orig_trx_receipts_size);
|
||||
bb._pending_trx_metas.resize(orig_trx_metas_size);
|
||||
if( std::holds_alternative<digests_t>(bb._trx_mroot_or_receipt_digests) )
|
||||
std::get<digests_t>(bb._trx_mroot_or_receipt_digests).resize(orig_trx_receipt_digests_size);
|
||||
bb._pending_trx_receipts.resize(orig_block_transactions_size);
|
||||
bb._pending_trx_metas.resize(orig_state_transactions_size);
|
||||
bb._action_receipt_digests.resize(orig_action_receipt_digests_size);
|
||||
};
|
||||
|
||||
@@ -1255,7 +1228,6 @@ struct controller_impl {
|
||||
uint32_t billed_cpu_time_us, bool explicit_billed_cpu_time = false )
|
||||
{ try {
|
||||
|
||||
auto start = fc::time_point::now();
|
||||
const bool validating = !self.is_producing_block();
|
||||
EOS_ASSERT( !validating || explicit_billed_cpu_time, transaction_exception, "validating requires explicit billing" );
|
||||
|
||||
@@ -1295,10 +1267,6 @@ struct controller_impl {
|
||||
trace->scheduled = true;
|
||||
trace->receipt = push_receipt( gtrx.trx_id, transaction_receipt::expired, billed_cpu_time_us, 0 ); // expire the transaction
|
||||
trace->account_ram_delta = account_delta( gtrx.payer, trx_removal_ram_delta );
|
||||
trace->elapsed = fc::time_point::now() - start;
|
||||
pending->_block_report.total_cpu_usage_us += billed_cpu_time_us;
|
||||
pending->_block_report.total_elapsed_time += trace->elapsed;
|
||||
pending->_block_report.total_time += trace->elapsed;
|
||||
emit( self.accepted_transaction, trx );
|
||||
dmlog_applied_transaction(trace);
|
||||
emit( self.applied_transaction, std::tie(trace, trx->packed_trx()) );
|
||||
@@ -1329,7 +1297,7 @@ struct controller_impl {
|
||||
trace->error_code = controller::convert_exception_to_error_code( e );
|
||||
trace->except = e;
|
||||
trace->except_ptr = std::current_exception();
|
||||
trace->elapsed = fc::time_point::now() - start;
|
||||
trace->elapsed = fc::time_point::now() - trx_context.start;
|
||||
|
||||
if (auto dm_logger = get_deep_mind_logger()) {
|
||||
dm_logger->on_fail_deferred();
|
||||
@@ -1373,11 +1341,6 @@ struct controller_impl {
|
||||
|
||||
restore.cancel();
|
||||
|
||||
pending->_block_report.total_net_usage += trace->net_usage;
|
||||
pending->_block_report.total_cpu_usage_us += trace->receipt->cpu_usage_us;
|
||||
pending->_block_report.total_elapsed_time += trace->elapsed;
|
||||
pending->_block_report.total_time += fc::time_point::now() - start;
|
||||
|
||||
return trace;
|
||||
} catch( const disallowed_transaction_extensions_bad_block_exception& ) {
|
||||
throw;
|
||||
@@ -1408,18 +1371,13 @@ struct controller_impl {
|
||||
trace = error_trace;
|
||||
if( !trace->except_ptr ) {
|
||||
trace->account_ram_delta = account_delta( gtrx.payer, trx_removal_ram_delta );
|
||||
trace->elapsed = fc::time_point::now() - start;
|
||||
emit( self.accepted_transaction, trx );
|
||||
dmlog_applied_transaction(trace);
|
||||
emit( self.applied_transaction, std::tie(trace, trx->packed_trx()) );
|
||||
undo_session.squash();
|
||||
pending->_block_report.total_net_usage += trace->net_usage;
|
||||
if( trace->receipt ) pending->_block_report.total_cpu_usage_us += trace->receipt->cpu_usage_us;
|
||||
pending->_block_report.total_elapsed_time += trace->elapsed;
|
||||
pending->_block_report.total_time += trace->elapsed;
|
||||
return trace;
|
||||
}
|
||||
trace->elapsed = fc::time_point::now() - start;
|
||||
trace->elapsed = fc::time_point::now() - trx_context.start;
|
||||
}
|
||||
|
||||
// Only subjective OR hard failure logic below:
|
||||
@@ -1466,11 +1424,6 @@ struct controller_impl {
|
||||
emit( self.applied_transaction, std::tie(trace, trx->packed_trx()) );
|
||||
}
|
||||
|
||||
pending->_block_report.total_net_usage += trace->net_usage;
|
||||
if( trace->receipt ) pending->_block_report.total_cpu_usage_us += trace->receipt->cpu_usage_us;
|
||||
pending->_block_report.total_elapsed_time += trace->elapsed;
|
||||
pending->_block_report.total_time += fc::time_point::now() - start;
|
||||
|
||||
return trace;
|
||||
} FC_CAPTURE_AND_RETHROW() } /// push_scheduled_transaction
|
||||
|
||||
@@ -1489,9 +1442,6 @@ struct controller_impl {
|
||||
r.cpu_usage_us = cpu_usage_us;
|
||||
r.net_usage_words = net_usage_words;
|
||||
r.status = status;
|
||||
auto& bb = std::get<building_block>(pending->_block_stage);
|
||||
if( std::holds_alternative<digests_t>(bb._trx_mroot_or_receipt_digests) )
|
||||
std::get<digests_t>(bb._trx_mroot_or_receipt_digests).emplace_back( r.digest() );
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -1611,13 +1561,6 @@ struct controller_impl {
|
||||
trx_context.squash();
|
||||
}
|
||||
|
||||
if( !trx->read_only ) {
|
||||
pending->_block_report.total_net_usage += trace->net_usage;
|
||||
pending->_block_report.total_cpu_usage_us += trace->receipt->cpu_usage_us;
|
||||
pending->_block_report.total_elapsed_time += trace->elapsed;
|
||||
pending->_block_report.total_time += fc::time_point::now() - start;
|
||||
}
|
||||
|
||||
return trace;
|
||||
} catch( const disallowed_transaction_extensions_bad_block_exception& ) {
|
||||
throw;
|
||||
@@ -1635,14 +1578,9 @@ struct controller_impl {
|
||||
}
|
||||
|
||||
if (!trx->read_only) {
|
||||
emit(self.accepted_transaction, trx);
|
||||
dmlog_applied_transaction(trace);
|
||||
emit(self.applied_transaction, std::tie(trace, trx->packed_trx()));
|
||||
|
||||
pending->_block_report.total_net_usage += trace->net_usage;
|
||||
if( trace->receipt ) pending->_block_report.total_cpu_usage_us += trace->receipt->cpu_usage_us;
|
||||
pending->_block_report.total_elapsed_time += trace->elapsed;
|
||||
pending->_block_report.total_time += fc::time_point::now() - start;
|
||||
emit(self.accepted_transaction, trx);
|
||||
dmlog_applied_transaction(trace);
|
||||
emit(self.applied_transaction, std::tie(trace, trx->packed_trx()));
|
||||
}
|
||||
|
||||
return trace;
|
||||
@@ -1754,7 +1692,7 @@ struct controller_impl {
|
||||
});
|
||||
}
|
||||
|
||||
const auto& gpo = self.get_global_properties();
|
||||
const auto& gpo = db.get<global_property_object>();
|
||||
|
||||
if( gpo.proposed_schedule_block_num && // if there is a proposed schedule that was proposed in a block ...
|
||||
( *gpo.proposed_schedule_block_num <= pbhs.dpos_irreversible_blocknum ) && // ... that has now become irreversible ...
|
||||
@@ -1789,7 +1727,7 @@ struct controller_impl {
|
||||
});
|
||||
in_trx_requiring_checks = true;
|
||||
auto trace = push_transaction( onbtrx, fc::time_point::maximum(), fc::microseconds::maximum(),
|
||||
gpo.configuration.min_transaction_cpu_usage, true, 0 );
|
||||
self.get_global_properties().configuration.min_transaction_cpu_usage, true, 0 );
|
||||
if( trace->except ) {
|
||||
wlog("onblock ${block_num} is REJECTING: ${entire_trace}",("block_num", head->block_num + 1)("entire_trace", trace));
|
||||
}
|
||||
@@ -1825,21 +1763,6 @@ struct controller_impl {
|
||||
|
||||
auto& pbhs = pending->get_pending_block_header_state();
|
||||
|
||||
auto& bb = std::get<building_block>(pending->_block_stage);
|
||||
|
||||
auto action_merkle_fut = async_thread_pool( thread_pool.get_executor(),
|
||||
[ids{std::move( bb._action_receipt_digests )}]() mutable {
|
||||
return merkle( std::move( ids ) );
|
||||
} );
|
||||
const bool calc_trx_merkle = !std::holds_alternative<checksum256_type>(bb._trx_mroot_or_receipt_digests);
|
||||
std::future<checksum256_type> trx_merkle_fut;
|
||||
if( calc_trx_merkle ) {
|
||||
trx_merkle_fut = async_thread_pool( thread_pool.get_executor(),
|
||||
[ids{std::move( std::get<digests_t>(bb._trx_mroot_or_receipt_digests) )}]() mutable {
|
||||
return merkle( std::move( ids ) );
|
||||
} );
|
||||
}
|
||||
|
||||
// Update resource limits:
|
||||
resource_limits.process_account_limit_updates();
|
||||
const auto& chain_config = self.get_global_properties().configuration;
|
||||
@@ -1850,10 +1773,12 @@ struct controller_impl {
|
||||
);
|
||||
resource_limits.process_block_usage(pbhs.block_num);
|
||||
|
||||
auto& bb = std::get<building_block>(pending->_block_stage);
|
||||
|
||||
// Create (unsigned) block:
|
||||
auto block_ptr = std::make_shared<signed_block>( pbhs.make_block_header(
|
||||
calc_trx_merkle ? trx_merkle_fut.get() : std::get<checksum256_type>(bb._trx_mroot_or_receipt_digests),
|
||||
action_merkle_fut.get(),
|
||||
bb._transaction_mroot ? *bb._transaction_mroot : calculate_trx_merkle( bb._pending_trx_receipts ),
|
||||
merkle( std::move( std::get<building_block>(pending->_block_stage)._action_receipt_digests ) ),
|
||||
bb._new_pending_producer_schedule,
|
||||
std::move( bb._new_protocol_feature_activations ),
|
||||
protocol_features.get_protocol_feature_set()
|
||||
@@ -2013,20 +1938,15 @@ struct controller_impl {
|
||||
}
|
||||
|
||||
|
||||
void apply_block( controller::block_report& br, const block_state_ptr& bsp, controller::block_status s,
|
||||
const trx_meta_cache_lookup& trx_lookup )
|
||||
void apply_block( const block_state_ptr& bsp, controller::block_status s, const trx_meta_cache_lookup& trx_lookup )
|
||||
{ try {
|
||||
try {
|
||||
auto start = fc::time_point::now();
|
||||
const signed_block_ptr& b = bsp->block;
|
||||
const auto& new_protocol_feature_activations = bsp->get_new_protocol_feature_activations();
|
||||
|
||||
auto producer_block_id = bsp->id;
|
||||
start_block( b->timestamp, b->confirmed, new_protocol_feature_activations, s, producer_block_id, fc::time_point::maximum() );
|
||||
|
||||
// validated in create_block_state_future()
|
||||
std::get<building_block>(pending->_block_stage)._trx_mroot_or_receipt_digests = b->transaction_mroot;
|
||||
|
||||
const bool existing_trxs_metas = !bsp->trxs_metas().empty();
|
||||
const bool pub_keys_recovered = bsp->is_pub_keys_recovered();
|
||||
const bool skip_auth_checks = self.skip_auth_check();
|
||||
@@ -2061,8 +1981,8 @@ struct controller_impl {
|
||||
transaction_trace_ptr trace;
|
||||
|
||||
size_t packed_idx = 0;
|
||||
const auto& trx_receipts = std::get<building_block>(pending->_block_stage)._pending_trx_receipts;
|
||||
for( const auto& receipt : b->transactions ) {
|
||||
const auto& trx_receipts = std::get<building_block>(pending->_block_stage)._pending_trx_receipts;
|
||||
auto num_pending_receipts = trx_receipts.size();
|
||||
if( std::holds_alternative<packed_transaction>(receipt.trx) ) {
|
||||
const auto& trx_meta = ( use_bsp_cached ? bsp->trxs_metas().at( packed_idx )
|
||||
@@ -2098,6 +2018,9 @@ struct controller_impl {
|
||||
("lhs", r)("rhs", static_cast<const transaction_receipt_header&>(receipt)) );
|
||||
}
|
||||
|
||||
// validated in create_block_state_future()
|
||||
std::get<building_block>(pending->_block_stage)._transaction_mroot = b->transaction_mroot;
|
||||
|
||||
finalize_block();
|
||||
|
||||
auto& ab = std::get<assembled_block>(pending->_block_stage);
|
||||
@@ -2116,9 +2039,7 @@ struct controller_impl {
|
||||
// create completed_block with the existing block_state as we just verified it is the same as assembled_block
|
||||
pending->_block_stage = completed_block{ bsp };
|
||||
|
||||
br = pending->_block_report; // copy before commit block destroys pending
|
||||
commit_block(false);
|
||||
br.total_time = fc::time_point::now() - start;
|
||||
return;
|
||||
} catch ( const std::bad_alloc& ) {
|
||||
throw;
|
||||
@@ -2135,44 +2056,64 @@ struct controller_impl {
|
||||
}
|
||||
} FC_CAPTURE_AND_RETHROW() } /// apply_block
|
||||
|
||||
|
||||
// thread safe, expected to be called from thread other than the main thread
|
||||
block_state_ptr create_block_state_i( const block_id_type& id, const signed_block_ptr& b, const block_header_state& prev ) {
|
||||
auto trx_mroot = calculate_trx_merkle( b->transactions );
|
||||
EOS_ASSERT( b->transaction_mroot == trx_mroot, block_validate_exception,
|
||||
"invalid block transaction merkle root ${b} != ${c}", ("b", b->transaction_mroot)("c", trx_mroot) );
|
||||
|
||||
const bool skip_validate_signee = false;
|
||||
auto bsp = std::make_shared<block_state>(
|
||||
prev,
|
||||
b,
|
||||
protocol_features.get_protocol_feature_set(),
|
||||
[this]( block_timestamp_type timestamp,
|
||||
const flat_set<digest_type>& cur_features,
|
||||
const vector<digest_type>& new_features )
|
||||
{ check_protocol_features( timestamp, cur_features, new_features ); },
|
||||
skip_validate_signee
|
||||
);
|
||||
|
||||
EOS_ASSERT( id == bsp->id, block_validate_exception,
|
||||
"provided id ${id} does not match block id ${bid}", ("id", id)("bid", bsp->id) );
|
||||
return bsp;
|
||||
}
|
||||
|
||||
std::future<block_state_ptr> create_block_state_future( const block_id_type& id, const signed_block_ptr& b ) {
|
||||
EOS_ASSERT( b, block_validate_exception, "null block" );
|
||||
|
||||
return async_thread_pool( thread_pool.get_executor(), [b, id, control=this]() {
|
||||
// no reason for a block_state if fork_db already knows about block
|
||||
auto existing = control->fork_db.get_block( id );
|
||||
EOS_ASSERT( !existing, fork_database_exception, "we already know about this block: ${id}", ("id", id) );
|
||||
|
||||
auto prev = control->fork_db.get_block_header( b->previous );
|
||||
EOS_ASSERT( prev, unlinkable_block_exception,
|
||||
"unlinkable block ${id}", ("id", id)("previous", b->previous) );
|
||||
|
||||
return control->create_block_state_i( id, b, *prev );
|
||||
} );
|
||||
}
|
||||
|
||||
// thread safe, expected to be called from thread other than the main thread
|
||||
block_state_ptr create_block_state( const block_id_type& id, const signed_block_ptr& b ) {
|
||||
EOS_ASSERT( b, block_validate_exception, "null block" );
|
||||
|
||||
// no reason for a block_state if fork_db already knows about block
|
||||
auto existing = fork_db.get_block( id );
|
||||
EOS_ASSERT( !existing, fork_database_exception, "we already know about this block: ${id}", ("id", id) );
|
||||
|
||||
// previous not found could mean that previous block not applied yet
|
||||
auto prev = fork_db.get_block_header( b->previous );
|
||||
EOS_ASSERT( prev, unlinkable_block_exception,
|
||||
"unlinkable block ${id}", ("id", id)("previous", b->previous) );
|
||||
if( !prev ) return {};
|
||||
|
||||
return async_thread_pool( thread_pool.get_executor(), [b, prev, id, control=this]() {
|
||||
const bool skip_validate_signee = false;
|
||||
|
||||
auto trx_mroot = calculate_trx_merkle( b->transactions );
|
||||
EOS_ASSERT( b->transaction_mroot == trx_mroot, block_validate_exception,
|
||||
"invalid block transaction merkle root ${b} != ${c}", ("b", b->transaction_mroot)("c", trx_mroot) );
|
||||
|
||||
auto bsp = std::make_shared<block_state>(
|
||||
*prev,
|
||||
move( b ),
|
||||
control->protocol_features.get_protocol_feature_set(),
|
||||
[control]( block_timestamp_type timestamp,
|
||||
const flat_set<digest_type>& cur_features,
|
||||
const vector<digest_type>& new_features )
|
||||
{ control->check_protocol_features( timestamp, cur_features, new_features ); },
|
||||
skip_validate_signee
|
||||
);
|
||||
|
||||
EOS_ASSERT( id == bsp->id, block_validate_exception,
|
||||
"provided id ${id} does not match block id ${bid}", ("id", id)("bid", bsp->id) );
|
||||
return bsp;
|
||||
} );
|
||||
return create_block_state_i( id, b, *prev );
|
||||
}
|
||||
|
||||
void push_block( controller::block_report& br,
|
||||
std::future<block_state_ptr>& block_state_future,
|
||||
const forked_branch_callback& forked_branch_cb, const trx_meta_cache_lookup& trx_lookup )
|
||||
void push_block( const block_state_ptr& bsp,
|
||||
const forked_branch_callback& forked_branch_cb,
|
||||
const trx_meta_cache_lookup& trx_lookup )
|
||||
{
|
||||
controller::block_status s = controller::block_status::complete;
|
||||
EOS_ASSERT(!pending, block_validate_exception, "it is not valid to push a block when there is a pending block");
|
||||
@@ -2181,10 +2122,10 @@ struct controller_impl {
|
||||
trusted_producer_light_validation = old_value;
|
||||
});
|
||||
try {
|
||||
block_state_ptr bsp = block_state_future.get();
|
||||
EOS_ASSERT( bsp, block_validate_exception, "null block" );
|
||||
const auto& b = bsp->block;
|
||||
|
||||
if( conf.terminate_at_block > 0 && conf.terminate_at_block < self.head_block_num()) {
|
||||
if( conf.terminate_at_block > 0 && conf.terminate_at_block <= self.head_block_num()) {
|
||||
ilog("Reached configured maximum block ${num}; terminating", ("num", conf.terminate_at_block) );
|
||||
shutdown();
|
||||
return;
|
||||
@@ -2201,7 +2142,7 @@ struct controller_impl {
|
||||
emit( self.accepted_block_header, bsp );
|
||||
|
||||
if( read_mode != db_read_mode::IRREVERSIBLE ) {
|
||||
maybe_switch_forks( br, fork_db.pending_head(), s, forked_branch_cb, trx_lookup );
|
||||
maybe_switch_forks( fork_db.pending_head(), s, forked_branch_cb, trx_lookup );
|
||||
} else {
|
||||
log_irreversible();
|
||||
}
|
||||
@@ -2219,7 +2160,7 @@ struct controller_impl {
|
||||
EOS_ASSERT( (s == controller::block_status::irreversible || s == controller::block_status::validated),
|
||||
block_validate_exception, "invalid block status for replay" );
|
||||
|
||||
if( conf.terminate_at_block > 0 && conf.terminate_at_block < self.head_block_num() ) {
|
||||
if( conf.terminate_at_block > 0 && conf.terminate_at_block <= self.head_block_num() ) {
|
||||
ilog("Reached configured maximum block ${num}; terminating", ("num", conf.terminate_at_block) );
|
||||
shutdown();
|
||||
return;
|
||||
@@ -2245,9 +2186,8 @@ struct controller_impl {
|
||||
|
||||
emit( self.accepted_block_header, bsp );
|
||||
|
||||
controller::block_report br;
|
||||
if( s == controller::block_status::irreversible ) {
|
||||
apply_block( br, bsp, s, trx_meta_cache_lookup{} );
|
||||
apply_block( bsp, s, trx_meta_cache_lookup{} );
|
||||
head = bsp;
|
||||
|
||||
// On replay, log_irreversible is not called and so no irreversible_block signal is emitted.
|
||||
@@ -2261,19 +2201,19 @@ struct controller_impl {
|
||||
} else {
|
||||
EOS_ASSERT( read_mode != db_read_mode::IRREVERSIBLE, block_validate_exception,
|
||||
"invariant failure: cannot replay reversible blocks while in irreversible mode" );
|
||||
maybe_switch_forks( br, bsp, s, forked_branch_callback{}, trx_meta_cache_lookup{} );
|
||||
maybe_switch_forks( bsp, s, forked_branch_callback{}, trx_meta_cache_lookup{} );
|
||||
}
|
||||
|
||||
} FC_LOG_AND_RETHROW( )
|
||||
}
|
||||
|
||||
void maybe_switch_forks( controller::block_report& br, const block_state_ptr& new_head, controller::block_status s,
|
||||
void maybe_switch_forks( const block_state_ptr& new_head, controller::block_status s,
|
||||
const forked_branch_callback& forked_branch_cb, const trx_meta_cache_lookup& trx_lookup )
|
||||
{
|
||||
bool head_changed = true;
|
||||
if( new_head->header.previous == head->id ) {
|
||||
try {
|
||||
apply_block( br, new_head, s, trx_lookup );
|
||||
apply_block( new_head, s, trx_lookup );
|
||||
fork_db.mark_valid( new_head );
|
||||
head = new_head;
|
||||
} catch ( const std::exception& e ) {
|
||||
@@ -2304,9 +2244,8 @@ struct controller_impl {
|
||||
for( auto ritr = branches.first.rbegin(); ritr != branches.first.rend(); ++ritr ) {
|
||||
auto except = std::exception_ptr{};
|
||||
try {
|
||||
br = controller::block_report{};
|
||||
apply_block( br, *ritr, (*ritr)->is_valid() ? controller::block_status::validated
|
||||
: controller::block_status::complete, trx_lookup );
|
||||
apply_block( *ritr, (*ritr)->is_valid() ? controller::block_status::validated
|
||||
: controller::block_status::complete, trx_lookup );
|
||||
fork_db.mark_valid( *ritr );
|
||||
head = *ritr;
|
||||
} catch ( const std::bad_alloc& ) {
|
||||
@@ -2337,8 +2276,7 @@ struct controller_impl {
|
||||
|
||||
// re-apply good blocks
|
||||
for( auto ritr = branches.second.rbegin(); ritr != branches.second.rend(); ++ritr ) {
|
||||
br = controller::block_report{};
|
||||
apply_block( br, *ritr, controller::block_status::validated /* we previously validated these blocks*/, trx_lookup );
|
||||
apply_block( *ritr, controller::block_status::validated /* we previously validated these blocks*/, trx_lookup );
|
||||
head = *ritr;
|
||||
}
|
||||
std::rethrow_exception(except);
|
||||
@@ -2355,8 +2293,8 @@ struct controller_impl {
|
||||
|
||||
} /// push_block
|
||||
|
||||
deque<transaction_metadata_ptr> abort_block() {
|
||||
deque<transaction_metadata_ptr> applied_trxs;
|
||||
vector<transaction_metadata_ptr> abort_block() {
|
||||
vector<transaction_metadata_ptr> applied_trxs;
|
||||
if( pending ) {
|
||||
applied_trxs = pending->extract_trx_metas();
|
||||
pending.reset();
|
||||
@@ -2365,8 +2303,9 @@ struct controller_impl {
|
||||
return applied_trxs;
|
||||
}
|
||||
|
||||
static checksum256_type calculate_trx_merkle( const deque<transaction_receipt>& trxs ) {
|
||||
deque<digest_type> trx_digests;
|
||||
static checksum256_type calculate_trx_merkle( const vector<transaction_receipt>& trxs ) {
|
||||
vector<digest_type> trx_digests;
|
||||
trx_digests.reserve( trxs.size() );
|
||||
for( const auto& a : trxs )
|
||||
trx_digests.emplace_back( a.digest() );
|
||||
|
||||
@@ -2857,7 +2796,7 @@ void controller::start_block( block_timestamp_type when,
|
||||
block_status::incomplete, std::optional<block_id_type>(), deadline );
|
||||
}
|
||||
|
||||
block_state_ptr controller::finalize_block( block_report& br, const signer_callback_type& signer_callback ) {
|
||||
block_state_ptr controller::finalize_block( const signer_callback_type& signer_callback ) {
|
||||
validate_db_available_size();
|
||||
|
||||
my->finalize_block();
|
||||
@@ -2878,8 +2817,6 @@ block_state_ptr controller::finalize_block( block_report& br, const signer_callb
|
||||
|
||||
my->pending->_block_stage = completed_block{ bsp };
|
||||
|
||||
br = my->pending->_block_report;
|
||||
|
||||
return bsp;
|
||||
}
|
||||
|
||||
@@ -2888,7 +2825,7 @@ void controller::commit_block() {
|
||||
my->commit_block(true);
|
||||
}
|
||||
|
||||
deque<transaction_metadata_ptr> controller::abort_block() {
|
||||
vector<transaction_metadata_ptr> controller::abort_block() {
|
||||
return my->abort_block();
|
||||
}
|
||||
|
||||
@@ -2900,12 +2837,16 @@ std::future<block_state_ptr> controller::create_block_state_future( const block_
|
||||
return my->create_block_state_future( id, b );
|
||||
}
|
||||
|
||||
void controller::push_block( controller::block_report& br,
|
||||
std::future<block_state_ptr>& block_state_future,
|
||||
const forked_branch_callback& forked_branch_cb, const trx_meta_cache_lookup& trx_lookup )
|
||||
block_state_ptr controller::create_block_state( const block_id_type& id, const signed_block_ptr& b ) const {
|
||||
return my->create_block_state( id, b );
|
||||
}
|
||||
|
||||
void controller::push_block( const block_state_ptr& bsp,
|
||||
const forked_branch_callback& forked_branch_cb,
|
||||
const trx_meta_cache_lookup& trx_lookup )
|
||||
{
|
||||
validate_db_available_size();
|
||||
my->push_block( br, block_state_future, forked_branch_cb, trx_lookup );
|
||||
my->push_block( bsp, forked_branch_cb, trx_lookup );
|
||||
}
|
||||
|
||||
transaction_trace_ptr controller::push_transaction( const transaction_metadata_ptr& trx,
|
||||
@@ -3061,6 +3002,11 @@ std::optional<block_id_type> controller::pending_producer_block_id()const {
|
||||
return my->pending->_producer_block_id;
|
||||
}
|
||||
|
||||
const vector<transaction_receipt>& controller::get_pending_trx_receipts()const {
|
||||
EOS_ASSERT( my->pending, block_validate_exception, "no pending block" );
|
||||
return my->pending->get_trx_receipts();
|
||||
}
|
||||
|
||||
uint32_t controller::last_irreversible_block_num() const {
|
||||
return my->fork_db.root()->block_num;
|
||||
}
|
||||
@@ -3552,7 +3498,11 @@ std::optional<chain_id_type> controller::extract_chain_id_from_db( const path& s
|
||||
if (gpo==nullptr) return {};
|
||||
|
||||
return gpo->chain_id;
|
||||
} catch (std::system_error &) {} // do not propagate db_error_code::not_found" for absent db, so it will be created
|
||||
} catch( const std::system_error& e ) {
|
||||
// do not propagate db_error_code::not_found for absent db, so it will be created
|
||||
if( e.code().value() != chainbase::db_error_code::not_found )
|
||||
throw;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -42,7 +42,6 @@ namespace eosio::chain {
|
||||
case deep_mind_handler::operation_qualifier::none: return "";
|
||||
case deep_mind_handler::operation_qualifier::modify: return "MODIFY_";
|
||||
case deep_mind_handler::operation_qualifier::push: return "PUSH_";
|
||||
default: elog("Unknown operation_qualifier"); return "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <boost/multi_index/composite_key.hpp>
|
||||
#include <fc/io/fstream.hpp>
|
||||
#include <fstream>
|
||||
#include <shared_mutex>
|
||||
|
||||
namespace eosio { namespace chain {
|
||||
using boost::multi_index_container;
|
||||
@@ -60,27 +61,44 @@ namespace eosio { namespace chain {
|
||||
}
|
||||
|
||||
struct fork_database_impl {
|
||||
fork_database_impl( fork_database& self, const fc::path& data_dir )
|
||||
:self(self)
|
||||
,datadir(data_dir)
|
||||
explicit fork_database_impl( const fc::path& data_dir )
|
||||
:datadir(data_dir)
|
||||
{}
|
||||
|
||||
fork_database& self;
|
||||
std::shared_mutex mtx;
|
||||
fork_multi_index_type index;
|
||||
block_state_ptr root; // Only uses the block_header_state portion
|
||||
block_state_ptr head;
|
||||
fc::path datadir;
|
||||
|
||||
void add( const block_state_ptr& n,
|
||||
bool ignore_duplicate, bool validate,
|
||||
const std::function<void( block_timestamp_type,
|
||||
const flat_set<digest_type>&,
|
||||
const vector<digest_type>& )>& validator );
|
||||
void open_impl( const std::function<void( block_timestamp_type,
|
||||
const flat_set<digest_type>&,
|
||||
const vector<digest_type>& )>& validator );
|
||||
void close_impl();
|
||||
|
||||
|
||||
block_header_state_ptr get_block_header_impl( const block_id_type& id )const;
|
||||
block_state_ptr get_block_impl( const block_id_type& id )const;
|
||||
void reset_impl( const block_header_state& root_bhs );
|
||||
void rollback_head_to_root_impl();
|
||||
void advance_root_impl( const block_id_type& id );
|
||||
void remove_impl( const block_id_type& id );
|
||||
branch_type fetch_branch_impl( const block_id_type& h, uint32_t trim_after_block_num )const;
|
||||
block_state_ptr search_on_branch_impl( const block_id_type& h, uint32_t block_num )const;
|
||||
pair<branch_type, branch_type> fetch_branch_from_impl( const block_id_type& first,
|
||||
const block_id_type& second )const;
|
||||
void mark_valid_impl( const block_state_ptr& h );
|
||||
|
||||
void add_impl( const block_state_ptr& n,
|
||||
bool ignore_duplicate, bool validate,
|
||||
const std::function<void( block_timestamp_type,
|
||||
const flat_set<digest_type>&,
|
||||
const vector<digest_type>& )>& validator );
|
||||
};
|
||||
|
||||
|
||||
fork_database::fork_database( const fc::path& data_dir )
|
||||
:my( new fork_database_impl( *this, data_dir ) )
|
||||
:my( new fork_database_impl( data_dir ) )
|
||||
{}
|
||||
|
||||
|
||||
@@ -88,10 +106,18 @@ namespace eosio { namespace chain {
|
||||
const flat_set<digest_type>&,
|
||||
const vector<digest_type>& )>& validator )
|
||||
{
|
||||
if (!fc::is_directory(my->datadir))
|
||||
fc::create_directories(my->datadir);
|
||||
std::lock_guard g( my->mtx );
|
||||
my->open_impl( validator );
|
||||
}
|
||||
|
||||
auto fork_db_dat = my->datadir / config::forkdb_filename;
|
||||
void fork_database_impl::open_impl( const std::function<void( block_timestamp_type,
|
||||
const flat_set<digest_type>&,
|
||||
const vector<digest_type>& )>& validator )
|
||||
{
|
||||
if (!fc::is_directory(datadir))
|
||||
fc::create_directories(datadir);
|
||||
|
||||
auto fork_db_dat = datadir / config::forkdb_filename;
|
||||
if( fc::exists( fork_db_dat ) ) {
|
||||
try {
|
||||
string content;
|
||||
@@ -102,29 +128,29 @@ namespace eosio { namespace chain {
|
||||
// validate totem
|
||||
uint32_t totem = 0;
|
||||
fc::raw::unpack( ds, totem );
|
||||
EOS_ASSERT( totem == magic_number, fork_database_exception,
|
||||
EOS_ASSERT( totem == fork_database::magic_number, fork_database_exception,
|
||||
"Fork database file '${filename}' has unexpected magic number: ${actual_totem}. Expected ${expected_totem}",
|
||||
("filename", fork_db_dat.generic_string())
|
||||
("actual_totem", totem)
|
||||
("expected_totem", magic_number)
|
||||
("expected_totem", fork_database::magic_number)
|
||||
);
|
||||
|
||||
// validate version
|
||||
uint32_t version = 0;
|
||||
fc::raw::unpack( ds, version );
|
||||
EOS_ASSERT( version >= min_supported_version && version <= max_supported_version,
|
||||
EOS_ASSERT( version >= fork_database::min_supported_version && version <= fork_database::max_supported_version,
|
||||
fork_database_exception,
|
||||
"Unsupported version of fork database file '${filename}'. "
|
||||
"Fork database version is ${version} while code supports version(s) [${min},${max}]",
|
||||
("filename", fork_db_dat.generic_string())
|
||||
("version", version)
|
||||
("min", min_supported_version)
|
||||
("max", max_supported_version)
|
||||
("min", fork_database::min_supported_version)
|
||||
("max", fork_database::max_supported_version)
|
||||
);
|
||||
|
||||
block_header_state bhs;
|
||||
fc::raw::unpack( ds, bhs );
|
||||
reset( bhs );
|
||||
reset_impl( bhs );
|
||||
|
||||
unsigned_int size; fc::raw::unpack( ds, size );
|
||||
for( uint32_t i = 0, n = size.value; i < n; ++i ) {
|
||||
@@ -132,27 +158,27 @@ namespace eosio { namespace chain {
|
||||
fc::raw::unpack( ds, s );
|
||||
// do not populate transaction_metadatas, they will be created as needed in apply_block with appropriate key recovery
|
||||
s.header_exts = s.block->validate_and_extract_header_extensions();
|
||||
my->add( std::make_shared<block_state>( move( s ) ), false, true, validator );
|
||||
add_impl( std::make_shared<block_state>( std::move( s ) ), false, true, validator );
|
||||
}
|
||||
block_id_type head_id;
|
||||
fc::raw::unpack( ds, head_id );
|
||||
|
||||
if( my->root->id == head_id ) {
|
||||
my->head = my->root;
|
||||
if( root->id == head_id ) {
|
||||
head = root;
|
||||
} else {
|
||||
my->head = get_block( head_id );
|
||||
EOS_ASSERT( my->head, fork_database_exception,
|
||||
head = get_block_impl( head_id );
|
||||
EOS_ASSERT( head, fork_database_exception,
|
||||
"could not find head while reconstructing fork database from file; '${filename}' is likely corrupted",
|
||||
("filename", fork_db_dat.generic_string()) );
|
||||
}
|
||||
|
||||
auto candidate = my->index.get<by_lib_block_num>().begin();
|
||||
if( candidate == my->index.get<by_lib_block_num>().end() || !(*candidate)->is_valid() ) {
|
||||
EOS_ASSERT( my->head->id == my->root->id, fork_database_exception,
|
||||
auto candidate = index.get<by_lib_block_num>().begin();
|
||||
if( candidate == index.get<by_lib_block_num>().end() || !(*candidate)->is_valid() ) {
|
||||
EOS_ASSERT( head->id == root->id, fork_database_exception,
|
||||
"head not set to root despite no better option available; '${filename}' is likely corrupted",
|
||||
("filename", fork_db_dat.generic_string()) );
|
||||
} else {
|
||||
EOS_ASSERT( !first_preferred( **candidate, *my->head ), fork_database_exception,
|
||||
EOS_ASSERT( !first_preferred( **candidate, *head ), fork_database_exception,
|
||||
"head not set to best available option available; '${filename}' is likely corrupted",
|
||||
("filename", fork_db_dat.generic_string()) );
|
||||
}
|
||||
@@ -163,10 +189,15 @@ namespace eosio { namespace chain {
|
||||
}
|
||||
|
||||
void fork_database::close() {
|
||||
auto fork_db_dat = my->datadir / config::forkdb_filename;
|
||||
std::lock_guard g( my->mtx );
|
||||
my->close_impl();
|
||||
}
|
||||
|
||||
if( !my->root ) {
|
||||
if( my->index.size() > 0 ) {
|
||||
void fork_database_impl::close_impl() {
|
||||
auto fork_db_dat = datadir / config::forkdb_filename;
|
||||
|
||||
if( !root ) {
|
||||
if( index.size() > 0 ) {
|
||||
elog( "fork_database is in a bad state when closing; not writing out '${filename}'",
|
||||
("filename", fork_db_dat.generic_string()) );
|
||||
}
|
||||
@@ -174,13 +205,13 @@ namespace eosio { namespace chain {
|
||||
}
|
||||
|
||||
std::ofstream out( fork_db_dat.generic_string().c_str(), std::ios::out | std::ios::binary | std::ofstream::trunc );
|
||||
fc::raw::pack( out, magic_number );
|
||||
fc::raw::pack( out, max_supported_version ); // write out current version which is always max_supported_version
|
||||
fc::raw::pack( out, *static_cast<block_header_state*>(&*my->root) );
|
||||
uint32_t num_blocks_in_fork_db = my->index.size();
|
||||
fc::raw::pack( out, fork_database::magic_number );
|
||||
fc::raw::pack( out, fork_database::max_supported_version ); // write out current version which is always max_supported_version
|
||||
fc::raw::pack( out, *static_cast<block_header_state*>(&*root) );
|
||||
uint32_t num_blocks_in_fork_db = index.size();
|
||||
fc::raw::pack( out, unsigned_int{num_blocks_in_fork_db} );
|
||||
|
||||
const auto& indx = my->index.get<by_lib_block_num>();
|
||||
const auto& indx = index.get<by_lib_block_num>();
|
||||
|
||||
auto unvalidated_itr = indx.rbegin();
|
||||
auto unvalidated_end = boost::make_reverse_iterator( indx.lower_bound( false ) );
|
||||
@@ -215,30 +246,40 @@ namespace eosio { namespace chain {
|
||||
fc::raw::pack( out, *(*itr) );
|
||||
}
|
||||
|
||||
if( my->head ) {
|
||||
fc::raw::pack( out, my->head->id );
|
||||
if( head ) {
|
||||
fc::raw::pack( out, head->id );
|
||||
} else {
|
||||
elog( "head not set in fork database; '${filename}' will be corrupted",
|
||||
("filename", fork_db_dat.generic_string()) );
|
||||
}
|
||||
|
||||
my->index.clear();
|
||||
index.clear();
|
||||
}
|
||||
|
||||
fork_database::~fork_database() {
|
||||
close();
|
||||
my->close_impl();
|
||||
}
|
||||
|
||||
void fork_database::reset( const block_header_state& root_bhs ) {
|
||||
my->index.clear();
|
||||
my->root = std::make_shared<block_state>();
|
||||
static_cast<block_header_state&>(*my->root) = root_bhs;
|
||||
my->root->validated = true;
|
||||
my->head = my->root;
|
||||
std::lock_guard g( my->mtx );
|
||||
my->reset_impl(root_bhs);
|
||||
}
|
||||
|
||||
void fork_database_impl::reset_impl( const block_header_state& root_bhs ) {
|
||||
index.clear();
|
||||
root = std::make_shared<block_state>();
|
||||
static_cast<block_header_state&>(*root) = root_bhs;
|
||||
root->validated = true;
|
||||
head = root;
|
||||
}
|
||||
|
||||
void fork_database::rollback_head_to_root() {
|
||||
auto& by_id_idx = my->index.get<by_block_id>();
|
||||
std::lock_guard g( my->mtx );
|
||||
my->rollback_head_to_root_impl();
|
||||
}
|
||||
|
||||
void fork_database_impl::rollback_head_to_root_impl() {
|
||||
auto& by_id_idx = index.get<by_block_id>();
|
||||
auto itr = by_id_idx.begin();
|
||||
while (itr != by_id_idx.end()) {
|
||||
by_id_idx.modify( itr, [&]( block_state_ptr& bsp ) {
|
||||
@@ -246,13 +287,18 @@ namespace eosio { namespace chain {
|
||||
} );
|
||||
++itr;
|
||||
}
|
||||
my->head = my->root;
|
||||
head = root;
|
||||
}
|
||||
|
||||
void fork_database::advance_root( const block_id_type& id ) {
|
||||
EOS_ASSERT( my->root, fork_database_exception, "root not yet set" );
|
||||
std::lock_guard g( my->mtx );
|
||||
my->advance_root_impl( id );
|
||||
}
|
||||
|
||||
auto new_root = get_block( id );
|
||||
void fork_database_impl::advance_root_impl( const block_id_type& id ) {
|
||||
EOS_ASSERT( root, fork_database_exception, "root not yet set" );
|
||||
|
||||
auto new_root = get_block_impl( id );
|
||||
EOS_ASSERT( new_root, fork_database_exception,
|
||||
"cannot advance root to a block that does not exist in the fork database" );
|
||||
EOS_ASSERT( new_root->is_valid(), fork_database_exception,
|
||||
@@ -262,48 +308,53 @@ namespace eosio { namespace chain {
|
||||
deque<block_id_type> blocks_to_remove;
|
||||
for( auto b = new_root; b; ) {
|
||||
blocks_to_remove.emplace_back( b->header.previous );
|
||||
b = get_block( blocks_to_remove.back() );
|
||||
EOS_ASSERT( b || blocks_to_remove.back() == my->root->id, fork_database_exception, "invariant violation: orphaned branch was present in forked database" );
|
||||
b = get_block_impl( blocks_to_remove.back() );
|
||||
EOS_ASSERT( b || blocks_to_remove.back() == root->id, fork_database_exception, "invariant violation: orphaned branch was present in forked database" );
|
||||
}
|
||||
|
||||
// The new root block should be erased from the fork database index individually rather than with the remove method,
|
||||
// because we do not want the blocks branching off of it to be removed from the fork database.
|
||||
my->index.erase( my->index.find( id ) );
|
||||
index.erase( index.find( id ) );
|
||||
|
||||
// The other blocks to be removed are removed using the remove method so that orphaned branches do not remain in the fork database.
|
||||
for( const auto& block_id : blocks_to_remove ) {
|
||||
remove( block_id );
|
||||
remove_impl( block_id );
|
||||
}
|
||||
|
||||
// Even though fork database no longer needs block or trxs when a block state becomes a root of the tree,
|
||||
// avoid mutating the block state at all, for example clearing the block shared pointer, because other
|
||||
// parts of the code which run asynchronously may later expect it remain unmodified.
|
||||
|
||||
my->root = new_root;
|
||||
root = new_root;
|
||||
}
|
||||
|
||||
block_header_state_ptr fork_database::get_block_header( const block_id_type& id )const {
|
||||
if( my->root->id == id ) {
|
||||
return my->root;
|
||||
std::shared_lock g( my->mtx );
|
||||
return my->get_block_header_impl( id );
|
||||
}
|
||||
|
||||
block_header_state_ptr fork_database_impl::get_block_header_impl( const block_id_type& id )const {
|
||||
if( root->id == id ) {
|
||||
return root;
|
||||
}
|
||||
|
||||
auto itr = my->index.find( id );
|
||||
if( itr != my->index.end() )
|
||||
auto itr = index.find( id );
|
||||
if( itr != index.end() )
|
||||
return *itr;
|
||||
|
||||
return block_header_state_ptr();
|
||||
}
|
||||
|
||||
void fork_database_impl::add( const block_state_ptr& n,
|
||||
bool ignore_duplicate, bool validate,
|
||||
const std::function<void( block_timestamp_type,
|
||||
const flat_set<digest_type>&,
|
||||
const vector<digest_type>& )>& validator )
|
||||
void fork_database_impl::add_impl( const block_state_ptr& n,
|
||||
bool ignore_duplicate, bool validate,
|
||||
const std::function<void( block_timestamp_type,
|
||||
const flat_set<digest_type>&,
|
||||
const vector<digest_type>& )>& validator )
|
||||
{
|
||||
EOS_ASSERT( root, fork_database_exception, "root not yet set" );
|
||||
EOS_ASSERT( n, fork_database_exception, "attempt to add null block state" );
|
||||
|
||||
auto prev_bh = self.get_block_header( n->header.previous );
|
||||
auto prev_bh = get_block_header_impl( n->header.previous );
|
||||
|
||||
EOS_ASSERT( prev_bh, unlinkable_block_exception,
|
||||
"unlinkable block", ("id", n->id)("previous", n->header.previous) );
|
||||
@@ -332,19 +383,27 @@ namespace eosio { namespace chain {
|
||||
}
|
||||
|
||||
void fork_database::add( const block_state_ptr& n, bool ignore_duplicate ) {
|
||||
my->add( n, ignore_duplicate, false,
|
||||
[]( block_timestamp_type timestamp,
|
||||
const flat_set<digest_type>& cur_features,
|
||||
const vector<digest_type>& new_features )
|
||||
{}
|
||||
std::lock_guard g( my->mtx );
|
||||
my->add_impl( n, ignore_duplicate, false,
|
||||
[]( block_timestamp_type timestamp,
|
||||
const flat_set<digest_type>& cur_features,
|
||||
const vector<digest_type>& new_features )
|
||||
{}
|
||||
);
|
||||
}
|
||||
|
||||
const block_state_ptr& fork_database::root()const { return my->root; }
|
||||
block_state_ptr fork_database::root()const {
|
||||
std::shared_lock g( my->mtx );
|
||||
return my->root;
|
||||
}
|
||||
|
||||
const block_state_ptr& fork_database::head()const { return my->head; }
|
||||
block_state_ptr fork_database::head()const {
|
||||
std::shared_lock g( my->mtx );
|
||||
return my->head;
|
||||
}
|
||||
|
||||
block_state_ptr fork_database::pending_head()const {
|
||||
std::shared_lock g( my->mtx );
|
||||
const auto& indx = my->index.get<by_lib_block_num>();
|
||||
|
||||
auto itr = indx.lower_bound( false );
|
||||
@@ -357,8 +416,13 @@ namespace eosio { namespace chain {
|
||||
}
|
||||
|
||||
branch_type fork_database::fetch_branch( const block_id_type& h, uint32_t trim_after_block_num )const {
|
||||
std::shared_lock g( my->mtx );
|
||||
return my->fetch_branch_impl( h, trim_after_block_num );
|
||||
}
|
||||
|
||||
branch_type fork_database_impl::fetch_branch_impl( const block_id_type& h, uint32_t trim_after_block_num )const {
|
||||
branch_type result;
|
||||
for( auto s = get_block(h); s; s = get_block( s->header.previous ) ) {
|
||||
for( auto s = get_block_impl(h); s; s = get_block_impl( s->header.previous ) ) {
|
||||
if( s->block_num <= trim_after_block_num )
|
||||
result.push_back( s );
|
||||
}
|
||||
@@ -367,7 +431,12 @@ namespace eosio { namespace chain {
|
||||
}
|
||||
|
||||
block_state_ptr fork_database::search_on_branch( const block_id_type& h, uint32_t block_num )const {
|
||||
for( auto s = get_block(h); s; s = get_block( s->header.previous ) ) {
|
||||
std::shared_lock g( my->mtx );
|
||||
return my->search_on_branch_impl( h, block_num );
|
||||
}
|
||||
|
||||
block_state_ptr fork_database_impl::search_on_branch_impl( const block_id_type& h, uint32_t block_num )const {
|
||||
for( auto s = get_block_impl(h); s; s = get_block_impl( s->header.previous ) ) {
|
||||
if( s->block_num == block_num )
|
||||
return s;
|
||||
}
|
||||
@@ -381,9 +450,15 @@ namespace eosio { namespace chain {
|
||||
*/
|
||||
pair< branch_type, branch_type > fork_database::fetch_branch_from( const block_id_type& first,
|
||||
const block_id_type& second )const {
|
||||
std::shared_lock g( my->mtx );
|
||||
return my->fetch_branch_from_impl( first, second );
|
||||
}
|
||||
|
||||
pair< branch_type, branch_type > fork_database_impl::fetch_branch_from_impl( const block_id_type& first,
|
||||
const block_id_type& second )const {
|
||||
pair<branch_type,branch_type> result;
|
||||
auto first_branch = (first == my->root->id) ? my->root : get_block(first);
|
||||
auto second_branch = (second == my->root->id) ? my->root : get_block(second);
|
||||
auto first_branch = (first == root->id) ? root : get_block_impl(first);
|
||||
auto second_branch = (second == root->id) ? root : get_block_impl(second);
|
||||
|
||||
EOS_ASSERT(first_branch, fork_db_block_not_found, "block ${id} does not exist", ("id", first));
|
||||
EOS_ASSERT(second_branch, fork_db_block_not_found, "block ${id} does not exist", ("id", second));
|
||||
@@ -392,7 +467,7 @@ namespace eosio { namespace chain {
|
||||
{
|
||||
result.first.push_back(first_branch);
|
||||
const auto& prev = first_branch->header.previous;
|
||||
first_branch = (prev == my->root->id) ? my->root : get_block( prev );
|
||||
first_branch = (prev == root->id) ? root : get_block_impl( prev );
|
||||
EOS_ASSERT( first_branch, fork_db_block_not_found,
|
||||
"block ${id} does not exist",
|
||||
("id", prev)
|
||||
@@ -403,7 +478,7 @@ namespace eosio { namespace chain {
|
||||
{
|
||||
result.second.push_back( second_branch );
|
||||
const auto& prev = second_branch->header.previous;
|
||||
second_branch = (prev == my->root->id) ? my->root : get_block( prev );
|
||||
second_branch = (prev == root->id) ? root : get_block_impl( prev );
|
||||
EOS_ASSERT( second_branch, fork_db_block_not_found,
|
||||
"block ${id} does not exist",
|
||||
("id", prev)
|
||||
@@ -417,9 +492,9 @@ namespace eosio { namespace chain {
|
||||
result.first.push_back(first_branch);
|
||||
result.second.push_back(second_branch);
|
||||
const auto &first_prev = first_branch->header.previous;
|
||||
first_branch = get_block( first_prev );
|
||||
first_branch = get_block_impl( first_prev );
|
||||
const auto &second_prev = second_branch->header.previous;
|
||||
second_branch = get_block( second_prev );
|
||||
second_branch = get_block_impl( second_prev );
|
||||
EOS_ASSERT( first_branch, fork_db_block_not_found,
|
||||
"block ${id} does not exist",
|
||||
("id", first_prev)
|
||||
@@ -436,13 +511,18 @@ namespace eosio { namespace chain {
|
||||
result.second.push_back(second_branch);
|
||||
}
|
||||
return result;
|
||||
} /// fetch_branch_from
|
||||
} /// fetch_branch_from_impl
|
||||
|
||||
/// remove all of the invalid forks built off of this id including this id
|
||||
void fork_database::remove( const block_id_type& id ) {
|
||||
std::lock_guard g( my->mtx );
|
||||
return my->remove_impl( id );
|
||||
}
|
||||
|
||||
void fork_database_impl::remove_impl( const block_id_type& id ) {
|
||||
deque<block_id_type> remove_queue{id};
|
||||
const auto& previdx = my->index.get<by_prev>();
|
||||
const auto& head_id = my->head->id;
|
||||
const auto& previdx = index.get<by_prev>();
|
||||
const auto& head_id = head->id;
|
||||
|
||||
for( uint32_t i = 0; i < remove_queue.size(); ++i ) {
|
||||
EOS_ASSERT( remove_queue[i] != head_id, fork_database_exception,
|
||||
@@ -456,16 +536,19 @@ namespace eosio { namespace chain {
|
||||
}
|
||||
|
||||
for( const auto& block_id : remove_queue ) {
|
||||
auto itr = my->index.find( block_id );
|
||||
if( itr != my->index.end() )
|
||||
my->index.erase(itr);
|
||||
index.erase( block_id );
|
||||
}
|
||||
}
|
||||
|
||||
void fork_database::mark_valid( const block_state_ptr& h ) {
|
||||
std::lock_guard g( my->mtx );
|
||||
my->mark_valid_impl( h );
|
||||
}
|
||||
|
||||
void fork_database_impl::mark_valid_impl( const block_state_ptr& h ) {
|
||||
if( h->validated ) return;
|
||||
|
||||
auto& by_id_idx = my->index.get<by_block_id>();
|
||||
auto& by_id_idx = index.get<by_block_id>();
|
||||
|
||||
auto itr = by_id_idx.find( h->id );
|
||||
EOS_ASSERT( itr != by_id_idx.end(), fork_database_exception,
|
||||
@@ -476,15 +559,20 @@ namespace eosio { namespace chain {
|
||||
bsp->validated = true;
|
||||
} );
|
||||
|
||||
auto candidate = my->index.get<by_lib_block_num>().begin();
|
||||
if( first_preferred( **candidate, *my->head ) ) {
|
||||
my->head = *candidate;
|
||||
auto candidate = index.get<by_lib_block_num>().begin();
|
||||
if( first_preferred( **candidate, *head ) ) {
|
||||
head = *candidate;
|
||||
}
|
||||
}
|
||||
|
||||
block_state_ptr fork_database::get_block(const block_id_type& id)const {
|
||||
auto itr = my->index.find( id );
|
||||
if( itr != my->index.end() )
|
||||
block_state_ptr fork_database::get_block(const block_id_type& id)const {
|
||||
std::shared_lock g( my->mtx );
|
||||
return my->get_block_impl(id);
|
||||
}
|
||||
|
||||
block_state_ptr fork_database_impl::get_block_impl(const block_id_type& id)const {
|
||||
auto itr = index.find( id );
|
||||
if( itr != index.end() )
|
||||
return *itr;
|
||||
return block_state_ptr();
|
||||
}
|
||||
|
||||
@@ -45,7 +45,6 @@ struct abi_serializer {
|
||||
/// @return string_view of `t` or internal string type
|
||||
std::string_view resolve_type(const std::string_view& t)const;
|
||||
bool is_array(const std::string_view& type)const;
|
||||
bool is_szarray(const std::string_view& type)const;
|
||||
bool is_optional(const std::string_view& type)const;
|
||||
bool is_type( const std::string_view& type, const yield_function_t& yield )const;
|
||||
[[deprecated("use the overload with yield_function_t[=create_yield_function(max_serialization_time)]")]]
|
||||
@@ -367,23 +366,6 @@ namespace impl {
|
||||
mvo(name, std::move(array));
|
||||
}
|
||||
|
||||
/**
|
||||
* template which overloads add for deques of types which contain ABI information in their trees
|
||||
* for these members we call ::add in order to trigger further processing
|
||||
*/
|
||||
template<typename M, typename Resolver, require_abi_t<M> = 1>
|
||||
static void add( mutable_variant_object &mvo, const char* name, const deque<M>& v, Resolver resolver, abi_traverse_context& ctx )
|
||||
{
|
||||
auto h = ctx.enter_scope();
|
||||
deque<fc::variant> array;
|
||||
|
||||
for (const auto& iter: v) {
|
||||
mutable_variant_object elem_mvo;
|
||||
add(elem_mvo, "_", iter, resolver, ctx);
|
||||
array.emplace_back(std::move(elem_mvo["_"]));
|
||||
}
|
||||
mvo(name, std::move(array));
|
||||
}
|
||||
/**
|
||||
* template which overloads add for shared_ptr of types which contain ABI information in their trees
|
||||
* for these members we call ::add in order to trigger further processing
|
||||
@@ -493,6 +475,7 @@ namespace impl {
|
||||
binary_to_variant_context _ctx(*abi, ctx, type);
|
||||
_ctx.short_path = true; // Just to be safe while avoiding the complexity of threading an override boolean all over the place
|
||||
mvo( "data", abi->_binary_to_variant( type, act.data, _ctx ));
|
||||
set_hex_data(mvo, "hex_data", act.data);
|
||||
} catch(...) {
|
||||
// any failure to serialize data, then leave as not serailzed
|
||||
set_hex_data(mvo, "data", act.data);
|
||||
@@ -506,7 +489,6 @@ namespace impl {
|
||||
} catch(...) {
|
||||
set_hex_data(mvo, "data", act.data);
|
||||
}
|
||||
set_hex_data(mvo, "hex_data", act.data);
|
||||
out(name, std::move(mvo));
|
||||
}
|
||||
|
||||
@@ -748,24 +730,6 @@ namespace impl {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* template which overloads extract for deque of types which contain ABI information in their trees
|
||||
* for these members we call ::extract in order to trigger further processing
|
||||
*/
|
||||
template<typename M, typename Resolver, require_abi_t<M> = 1>
|
||||
static void extract( const fc::variant& v, deque<M>& o, Resolver resolver, abi_traverse_context& ctx )
|
||||
{
|
||||
auto h = ctx.enter_scope();
|
||||
const variants& array = v.get_array();
|
||||
o.clear();
|
||||
for( auto itr = array.begin(); itr != array.end(); ++itr ) {
|
||||
M o_iter;
|
||||
extract(*itr, o_iter, resolver, ctx);
|
||||
o.emplace_back(std::move(o_iter));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* template which overloads extract for shared_ptr of types which contain ABI information in their trees
|
||||
* for these members we call ::extract in order to trigger further processing
|
||||
|
||||
@@ -84,10 +84,6 @@ struct permission_level_weight {
|
||||
friend bool operator == ( const permission_level_weight& lhs, const permission_level_weight& rhs ) {
|
||||
return tie( lhs.permission, lhs.weight ) == tie( rhs.permission, rhs.weight );
|
||||
}
|
||||
|
||||
friend bool operator < ( const permission_level_weight& lhs, const permission_level_weight& rhs ) {
|
||||
return tie( lhs.permission, lhs.weight ) < tie( rhs.permission, rhs.weight );
|
||||
}
|
||||
};
|
||||
|
||||
struct key_weight {
|
||||
@@ -97,10 +93,6 @@ struct key_weight {
|
||||
friend bool operator == ( const key_weight& lhs, const key_weight& rhs ) {
|
||||
return tie( lhs.key, lhs.weight ) == tie( rhs.key, rhs.weight );
|
||||
}
|
||||
|
||||
friend bool operator < ( const key_weight& lhs, const key_weight& rhs ) {
|
||||
return tie( lhs.key, lhs.weight ) < tie( rhs.key, rhs.weight );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -145,10 +137,6 @@ struct wait_weight {
|
||||
friend bool operator == ( const wait_weight& lhs, const wait_weight& rhs ) {
|
||||
return tie( lhs.wait_sec, lhs.weight ) == tie( rhs.wait_sec, rhs.weight );
|
||||
}
|
||||
|
||||
friend bool operator < ( const wait_weight& lhs, const wait_weight& rhs ) {
|
||||
return tie( lhs.wait_sec, lhs.weight ) < tie( rhs.wait_sec, rhs.weight );
|
||||
}
|
||||
};
|
||||
|
||||
namespace config {
|
||||
@@ -203,12 +191,6 @@ struct authority {
|
||||
friend bool operator != ( const authority& lhs, const authority& rhs ) {
|
||||
return tie( lhs.threshold, lhs.keys, lhs.accounts, lhs.waits ) != tie( rhs.threshold, rhs.keys, rhs.accounts, rhs.waits );
|
||||
}
|
||||
|
||||
void sort_fields () {
|
||||
std::sort(std::begin(keys), std::end(keys));
|
||||
std::sort(std::begin(accounts), std::end(accounts));
|
||||
std::sort(std::begin(waits), std::end(waits));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@ namespace eosio { namespace chain {
|
||||
signed_block& operator=(signed_block&&) = default;
|
||||
signed_block clone() const { return *this; }
|
||||
|
||||
deque<transaction_receipt> transactions; /// new or generated transactions
|
||||
vector<transaction_receipt> transactions; /// new or generated transactions
|
||||
extensions_type block_extensions;
|
||||
|
||||
flat_multimap<uint16_t, block_extension> validate_and_extract_extensions()const;
|
||||
|
||||
@@ -48,13 +48,10 @@ namespace eosio { namespace chain {
|
||||
block_log(block_log&& other);
|
||||
~block_log();
|
||||
|
||||
void append(const signed_block_ptr& b, const block_id_type& id);
|
||||
void append(const signed_block_ptr& b, const block_id_type& id, const std::vector<char>& packed_block);
|
||||
|
||||
void append(const signed_block_ptr& b);
|
||||
void flush();
|
||||
void reset( const genesis_state& gs, const signed_block_ptr& genesis_block );
|
||||
void reset( const chain_id_type& chain_id, uint32_t first_block_num );
|
||||
void remove(); // remove blocks.log and blocks.index
|
||||
|
||||
signed_block_ptr read_block(uint64_t file_pos)const;
|
||||
void read_block_header(block_header& bh, uint64_t file_pos)const;
|
||||
@@ -94,7 +91,7 @@ namespace eosio { namespace chain {
|
||||
|
||||
static bool is_pruned_log(const fc::path& data_dir);
|
||||
|
||||
static bool extract_block_range(const fc::path& block_dir, const fc::path&output_dir, block_num_type& start, block_num_type& end, bool rename_input=false);
|
||||
static bool trim_blocklog_front(const fc::path& block_dir, const fc::path& temp_dir, uint32_t truncate_at_block);
|
||||
|
||||
private:
|
||||
void open(const fc::path& data_dir);
|
||||
@@ -122,7 +119,6 @@ namespace eosio { namespace chain {
|
||||
FILE* ind_in = nullptr; //C style files for reading blocks.log and blocks.index
|
||||
//we use low level file IO because it is distinctly faster than C++ filebuf or iostream
|
||||
uint64_t first_block_pos = 0; //file position in blocks.log for the first block in the log
|
||||
genesis_state gs;
|
||||
chain_id_type chain_id;
|
||||
|
||||
static constexpr int blknum_offset{14}; //offset from start of block to 4 byte block number, valid for the only allowed versions
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace eosio { namespace chain {
|
||||
|
||||
block_state( pending_block_header_state&& cur,
|
||||
signed_block_ptr&& b, // unsigned block
|
||||
deque<transaction_metadata_ptr>&& trx_metas,
|
||||
vector<transaction_metadata_ptr>&& trx_metas,
|
||||
const protocol_feature_set& pfs,
|
||||
const std::function<void( block_timestamp_type,
|
||||
const flat_set<digest_type>&,
|
||||
@@ -44,24 +44,24 @@ namespace eosio { namespace chain {
|
||||
bool is_valid()const { return validated; }
|
||||
bool is_pub_keys_recovered()const { return _pub_keys_recovered; }
|
||||
|
||||
deque<transaction_metadata_ptr> extract_trxs_metas() {
|
||||
vector<transaction_metadata_ptr> extract_trxs_metas() {
|
||||
_pub_keys_recovered = false;
|
||||
auto result = std::move( _cached_trxs );
|
||||
_cached_trxs.clear();
|
||||
return result;
|
||||
}
|
||||
void set_trxs_metas( deque<transaction_metadata_ptr>&& trxs_metas, bool keys_recovered ) {
|
||||
void set_trxs_metas( vector<transaction_metadata_ptr>&& trxs_metas, bool keys_recovered ) {
|
||||
_pub_keys_recovered = keys_recovered;
|
||||
_cached_trxs = std::move( trxs_metas );
|
||||
}
|
||||
const deque<transaction_metadata_ptr>& trxs_metas()const { return _cached_trxs; }
|
||||
const vector<transaction_metadata_ptr>& trxs_metas()const { return _cached_trxs; }
|
||||
|
||||
bool validated = false;
|
||||
|
||||
bool _pub_keys_recovered = false;
|
||||
/// this data is redundant with the data stored in block, but facilitates
|
||||
/// recapturing transactions when we pop a block
|
||||
deque<transaction_metadata_ptr> _cached_trxs;
|
||||
vector<transaction_metadata_ptr> _cached_trxs;
|
||||
};
|
||||
|
||||
using block_state_ptr = std::shared_ptr<block_state>;
|
||||
|
||||
@@ -84,9 +84,7 @@ namespace eosio { namespace chain {
|
||||
bool allow_ram_billing_in_notify = false;
|
||||
uint32_t maximum_variable_signature_length = chain::config::default_max_variable_signature_length;
|
||||
bool disable_all_subjective_mitigations = false; //< for developer & testing purposes, can be configured using `disable-all-subjective-mitigations` when `EOSIO_DEVELOPER` build option is provided
|
||||
uint32_t terminate_at_block = 0; //< primarily for testing purposes
|
||||
bool integrity_hash_on_start= false;
|
||||
bool integrity_hash_on_stop = false;
|
||||
uint32_t terminate_at_block = 0;
|
||||
|
||||
wasm_interface::vm_type wasm_runtime = chain::config::default_wasm_runtime;
|
||||
eosvmoc::config eosvmoc_config;
|
||||
@@ -146,7 +144,7 @@ namespace eosio { namespace chain {
|
||||
/**
|
||||
* @return transactions applied in aborted block
|
||||
*/
|
||||
deque<transaction_metadata_ptr> abort_block();
|
||||
vector<transaction_metadata_ptr> abort_block();
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -164,27 +162,21 @@ namespace eosio { namespace chain {
|
||||
fc::time_point block_deadline, fc::microseconds max_transaction_time,
|
||||
uint32_t billed_cpu_time_us, bool explicit_billed_cpu_time );
|
||||
|
||||
struct block_report {
|
||||
size_t total_net_usage = 0;
|
||||
size_t total_cpu_usage_us = 0;
|
||||
fc::microseconds total_elapsed_time{};
|
||||
fc::microseconds total_time{};
|
||||
};
|
||||
|
||||
block_state_ptr finalize_block( block_report& br, const signer_callback_type& signer_callback );
|
||||
block_state_ptr finalize_block( const signer_callback_type& signer_callback );
|
||||
void sign_block( const signer_callback_type& signer_callback );
|
||||
void commit_block();
|
||||
|
||||
// thread-safe
|
||||
std::future<block_state_ptr> create_block_state_future( const block_id_type& id, const signed_block_ptr& b );
|
||||
// thread-safe
|
||||
block_state_ptr create_block_state( const block_id_type& id, const signed_block_ptr& b ) const;
|
||||
|
||||
/**
|
||||
* @param br returns statistics for block
|
||||
* @param block_state_future provide from call to create_block_state_future
|
||||
* @param bsp block to push
|
||||
* @param cb calls cb with forked applied transactions for each forked block
|
||||
* @param trx_lookup user provided lookup function for externally cached transaction_metadata
|
||||
*/
|
||||
void push_block( block_report& br,
|
||||
std::future<block_state_ptr>& block_state_future,
|
||||
void push_block( const block_state_ptr& bsp,
|
||||
const forked_branch_callback& cb,
|
||||
const trx_meta_cache_lookup& trx_lookup );
|
||||
|
||||
@@ -241,6 +233,8 @@ namespace eosio { namespace chain {
|
||||
std::optional<block_id_type> pending_producer_block_id()const;
|
||||
uint32_t pending_block_num()const;
|
||||
|
||||
const vector<transaction_receipt>& get_pending_trx_receipts()const;
|
||||
|
||||
const producer_authority_schedule& active_producers()const;
|
||||
const producer_authority_schedule& pending_producers()const;
|
||||
std::optional<producer_authority_schedule> proposed_producers()const;
|
||||
@@ -253,6 +247,7 @@ namespace eosio { namespace chain {
|
||||
signed_block_ptr fetch_block_by_id( block_id_type id )const;
|
||||
|
||||
block_state_ptr fetch_block_state_by_number( uint32_t block_num )const;
|
||||
// return block_state from forkdb, thread-safe
|
||||
block_state_ptr fetch_block_state_by_id( block_id_type id )const;
|
||||
|
||||
block_id_type get_block_id_for_num( uint32_t block_num )const;
|
||||
|
||||
@@ -186,6 +186,17 @@ namespace fc {
|
||||
b = eosio::chain::shared_blob(_s.begin(), _s.end(), b.get_allocator());
|
||||
}
|
||||
|
||||
inline
|
||||
void to_variant( const blob& b, variant& v ) {
|
||||
v = variant(base64_encode(b.data.data(), b.data.size()));
|
||||
}
|
||||
|
||||
inline
|
||||
void from_variant( const variant& v, blob& b ) {
|
||||
string _s = base64_decode(v.as_string());
|
||||
b.data = std::vector<char>(_s.begin(), _s.end());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void to_variant( const eosio::chain::shared_vector<T>& sv, variant& v ) {
|
||||
to_variant(std::vector<T>(sv.begin(), sv.end()), v);
|
||||
|
||||
@@ -16,6 +16,8 @@ namespace eosio { namespace chain {
|
||||
* database tracks the longest chain and the last irreversible block number. All
|
||||
* blocks older than the last irreversible block are freed after emitting the
|
||||
* irreversible signal.
|
||||
*
|
||||
* An internal mutex is used to provide thread-safety.
|
||||
*/
|
||||
class fork_database {
|
||||
public:
|
||||
@@ -55,9 +57,9 @@ namespace eosio { namespace chain {
|
||||
|
||||
void remove( const block_id_type& id );
|
||||
|
||||
const block_state_ptr& root()const;
|
||||
const block_state_ptr& head()const;
|
||||
block_state_ptr pending_head()const;
|
||||
block_state_ptr root()const;
|
||||
block_state_ptr head()const;
|
||||
block_state_ptr pending_head()const;
|
||||
|
||||
/**
|
||||
* Returns the sequence of block states resulting from trimming the branch from the
|
||||
|
||||
@@ -6,14 +6,11 @@
|
||||
namespace eosio { namespace chain {
|
||||
|
||||
/**
|
||||
* @brief limits for a kv database: NOT IN USE for mandel
|
||||
* @brief limits for a kv database.
|
||||
*
|
||||
* Each database (ram or disk, currently) has its own limits for these parameters.
|
||||
* The key and value limits apply when adding or modifying elements. They may be reduced
|
||||
* below existing database entries.
|
||||
*
|
||||
* This has been marked for removal at a later date, when v7 snapshots are deemed necessary.
|
||||
* kv_database_config will be removed as part of that effort.
|
||||
*/
|
||||
struct kv_database_config {
|
||||
std::uint32_t max_key_size = 0; ///< the maximum size in bytes of a key
|
||||
|
||||
@@ -17,6 +17,6 @@ namespace eosio { namespace chain {
|
||||
/**
|
||||
* Calculates the merkle root of a set of digests, if ids is odd it will duplicate the last id.
|
||||
*/
|
||||
digest_type merkle( deque<digest_type> ids );
|
||||
digest_type merkle( vector<digest_type> ids );
|
||||
|
||||
} } /// eosio::chain
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include <eosio/chain/config.hpp>
|
||||
#include <eosio/chain/trace.hpp>
|
||||
#include <eosio/chain/snapshot.hpp>
|
||||
#include <eosio/chain/block_timestamp.hpp>
|
||||
#include <chainbase/chainbase.hpp>
|
||||
#include <set>
|
||||
|
||||
@@ -57,8 +56,6 @@ namespace eosio { namespace chain {
|
||||
int64_t used = 0; ///< quantity used in current window
|
||||
int64_t available = 0; ///< quantity available in current window (based upon fractional reserve)
|
||||
int64_t max = 0; ///< max per window under current congestion
|
||||
block_timestamp_type last_usage_update_time; ///< last usage timestamp
|
||||
int64_t current_used = 0; ///< current usage according to the given timestamp
|
||||
};
|
||||
|
||||
class resource_limits_manager {
|
||||
@@ -105,10 +102,8 @@ namespace eosio { namespace chain {
|
||||
std::pair<int64_t, bool> get_account_cpu_limit( const account_name& name, uint32_t greylist_limit = config::maximum_elastic_resource_multiplier ) const;
|
||||
std::pair<int64_t, bool> get_account_net_limit( const account_name& name, uint32_t greylist_limit = config::maximum_elastic_resource_multiplier ) const;
|
||||
|
||||
std::pair<account_resource_limit, bool>
|
||||
get_account_cpu_limit_ex( const account_name& name, uint32_t greylist_limit = config::maximum_elastic_resource_multiplier, const std::optional<block_timestamp_type>& current_time={} ) const;
|
||||
std::pair<account_resource_limit, bool>
|
||||
get_account_net_limit_ex( const account_name& name, uint32_t greylist_limit = config::maximum_elastic_resource_multiplier, const std::optional<block_timestamp_type>& current_time={} ) const;
|
||||
std::pair<account_resource_limit, bool> get_account_cpu_limit_ex( const account_name& name, uint32_t greylist_limit = config::maximum_elastic_resource_multiplier ) const;
|
||||
std::pair<account_resource_limit, bool> get_account_net_limit_ex( const account_name& name, uint32_t greylist_limit = config::maximum_elastic_resource_multiplier ) const;
|
||||
|
||||
int64_t get_account_ram_usage( const account_name& name ) const;
|
||||
|
||||
@@ -118,6 +113,6 @@ namespace eosio { namespace chain {
|
||||
};
|
||||
} } } /// eosio::chain
|
||||
|
||||
FC_REFLECT( eosio::chain::resource_limits::account_resource_limit, (used)(available)(max)(last_usage_update_time)(current_used) )
|
||||
FC_REFLECT( eosio::chain::resource_limits::account_resource_limit, (used)(available)(max) )
|
||||
FC_REFLECT( eosio::chain::resource_limits::ratio, (numerator)(denominator))
|
||||
FC_REFLECT( eosio::chain::resource_limits::elastic_limit_parameters, (target)(max)(periods)(max_multiplier)(contract_rate)(expand_rate))
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include <fc/variant_object.hpp>
|
||||
#include <boost/core/demangle.hpp>
|
||||
#include <ostream>
|
||||
#include <memory>
|
||||
|
||||
namespace eosio { namespace chain {
|
||||
/**
|
||||
@@ -273,6 +272,11 @@ namespace eosio { namespace chain {
|
||||
read_section(detail::snapshot_section_traits<T>::section_name(), f);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool has_section(const std::string& suffix = std::string()) {
|
||||
return has_section(suffix + detail::snapshot_section_traits<T>::section_name());
|
||||
}
|
||||
|
||||
virtual void validate() const = 0;
|
||||
|
||||
virtual void return_to_header() = 0;
|
||||
@@ -280,6 +284,7 @@ namespace eosio { namespace chain {
|
||||
virtual ~snapshot_reader(){};
|
||||
|
||||
protected:
|
||||
virtual bool has_section( const std::string& section_name ) = 0;
|
||||
virtual void set_section( const std::string& section_name ) = 0;
|
||||
virtual bool read_row( detail::abstract_snapshot_row_reader& row_reader ) = 0;
|
||||
virtual bool empty( ) = 0;
|
||||
@@ -308,6 +313,7 @@ namespace eosio { namespace chain {
|
||||
explicit variant_snapshot_reader(const fc::variant& snapshot);
|
||||
|
||||
void validate() const override;
|
||||
bool has_section( const string& section_name ) override;
|
||||
void set_section( const string& section_name ) override;
|
||||
bool read_row( detail::abstract_snapshot_row_reader& row_reader ) override;
|
||||
bool empty ( ) override;
|
||||
@@ -336,22 +342,7 @@ namespace eosio { namespace chain {
|
||||
std::streampos header_pos;
|
||||
std::streampos section_pos;
|
||||
uint64_t row_count;
|
||||
};
|
||||
|
||||
class ostream_json_snapshot_writer : public snapshot_writer {
|
||||
public:
|
||||
explicit ostream_json_snapshot_writer(std::ostream& snapshot);
|
||||
|
||||
void write_start_section( const std::string& section_name ) override;
|
||||
void write_row( const detail::abstract_snapshot_row_writer& row_writer ) override;
|
||||
void write_end_section() override;
|
||||
void finalize();
|
||||
|
||||
static const uint32_t magic_number = 0x30510550;
|
||||
|
||||
private:
|
||||
detail::ostream_wrapper snapshot;
|
||||
uint64_t row_count;
|
||||
};
|
||||
|
||||
class istream_snapshot_reader : public snapshot_reader {
|
||||
@@ -359,6 +350,7 @@ namespace eosio { namespace chain {
|
||||
explicit istream_snapshot_reader(std::istream& snapshot);
|
||||
|
||||
void validate() const override;
|
||||
bool has_section( const string& section_name ) override;
|
||||
void set_section( const string& section_name ) override;
|
||||
bool read_row( detail::abstract_snapshot_row_reader& row_reader ) override;
|
||||
bool empty ( ) override;
|
||||
@@ -374,24 +366,6 @@ namespace eosio { namespace chain {
|
||||
uint64_t cur_row;
|
||||
};
|
||||
|
||||
class istream_json_snapshot_reader : public snapshot_reader {
|
||||
public:
|
||||
explicit istream_json_snapshot_reader(const fc::path& p);
|
||||
~istream_json_snapshot_reader();
|
||||
|
||||
void validate() const override;
|
||||
void set_section( const string& section_name ) override;
|
||||
bool read_row( detail::abstract_snapshot_row_reader& row_reader ) override;
|
||||
bool empty ( ) override;
|
||||
void clear_section() override;
|
||||
void return_to_header() override;
|
||||
|
||||
private:
|
||||
bool validate_section() const;
|
||||
|
||||
std::unique_ptr<struct istream_json_snapshot_reader_impl> impl;
|
||||
};
|
||||
|
||||
class integrity_hash_snapshot_writer : public snapshot_writer {
|
||||
public:
|
||||
explicit integrity_hash_snapshot_writer(fc::sha256::encoder& enc);
|
||||
|
||||
@@ -165,25 +165,6 @@ namespace eosio {
|
||||
return lhs.value() > rhs.value();
|
||||
}
|
||||
|
||||
inline bool operator== (const extended_symbol& lhs, const extended_symbol& rhs)
|
||||
{
|
||||
return std::tie(lhs.sym, lhs.contract) == std::tie(rhs.sym, rhs.contract);
|
||||
}
|
||||
|
||||
inline bool operator!= (const extended_symbol& lhs, const extended_symbol& rhs)
|
||||
{
|
||||
return std::tie(lhs.sym, lhs.contract) != std::tie(rhs.sym, rhs.contract);
|
||||
}
|
||||
|
||||
inline bool operator< (const extended_symbol& lhs, const extended_symbol& rhs)
|
||||
{
|
||||
return std::tie(lhs.sym, lhs.contract) < std::tie(rhs.sym, rhs.contract);
|
||||
}
|
||||
|
||||
inline bool operator> (const extended_symbol& lhs, const extended_symbol& rhs)
|
||||
{
|
||||
return std::tie(lhs.sym, lhs.contract) > std::tie(rhs.sym, rhs.contract);
|
||||
}
|
||||
} // namespace chain
|
||||
} // namespace eosio
|
||||
|
||||
|
||||
@@ -49,6 +49,12 @@ namespace eosio { namespace chain {
|
||||
* with a block_header::timestamp greater than expiration is
|
||||
* deemed irreversible, then a user can safely trust the transaction
|
||||
* will never be included.
|
||||
*
|
||||
|
||||
* Each region is an independent blockchain, it is included as routing
|
||||
* information for inter-blockchain communication. A contract in this
|
||||
* region might generate or authorize a transaction intended for a foreign
|
||||
* region.
|
||||
*/
|
||||
struct transaction_header {
|
||||
time_point_sec expiration; ///< the time at which a transaction expires
|
||||
@@ -70,7 +76,7 @@ namespace eosio { namespace chain {
|
||||
};
|
||||
|
||||
/**
|
||||
* A transaction consists of a set of messages which must all be applied or
|
||||
* A transaction consits of a set of messages which must all be applied or
|
||||
* all are rejected. These messages have access to data within the given
|
||||
* read and write scopes.
|
||||
*/
|
||||
|
||||
@@ -110,9 +110,9 @@ namespace eosio { namespace chain {
|
||||
void schedule_transaction();
|
||||
void record_transaction( const transaction_id_type& id, fc::time_point_sec expire );
|
||||
|
||||
void validate_cpu_usage_to_bill( int64_t billed_us, int64_t account_cpu_limit, bool check_minimum, int64_t subjective_billed_us )const;
|
||||
void validate_account_cpu_usage( int64_t billed_us, int64_t account_cpu_limit, int64_t subjective_billed_us )const;
|
||||
void validate_account_cpu_usage_estimate( int64_t billed_us, int64_t account_cpu_limit, int64_t subjective_billed_us )const;
|
||||
void validate_cpu_usage_to_bill( int64_t billed_us, int64_t account_cpu_limit, bool check_minimum )const;
|
||||
void validate_account_cpu_usage( int64_t billed_us, int64_t account_cpu_limit )const;
|
||||
void validate_account_cpu_usage_estimate( int64_t billed_us, int64_t account_cpu_limit )const;
|
||||
|
||||
void disallow_transaction_extensions( const char* error_msg )const;
|
||||
|
||||
@@ -128,7 +128,7 @@ namespace eosio { namespace chain {
|
||||
fc::time_point published;
|
||||
|
||||
|
||||
deque<digest_type> executed_action_receipt_digests;
|
||||
vector<digest_type> executed_action_receipt_digests;
|
||||
flat_set<account_name> bill_to_accounts;
|
||||
flat_set<account_name> validate_ram_usage;
|
||||
|
||||
|
||||
@@ -17,9 +17,6 @@
|
||||
#include <fc/fixed_string.hpp>
|
||||
#include <fc/crypto/private_key.hpp>
|
||||
|
||||
#include <boost/version.hpp>
|
||||
#include <boost/container/deque.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
@@ -48,6 +45,7 @@ namespace eosio { namespace chain {
|
||||
using std::vector;
|
||||
using std::unordered_map;
|
||||
using std::string;
|
||||
using std::deque;
|
||||
using std::shared_ptr;
|
||||
using std::weak_ptr;
|
||||
using std::unique_ptr;
|
||||
@@ -78,15 +76,7 @@ namespace eosio { namespace chain {
|
||||
using public_key_type = fc::crypto::public_key;
|
||||
using private_key_type = fc::crypto::private_key;
|
||||
using signature_type = fc::crypto::signature;
|
||||
#if BOOST_VERSION >= 107100
|
||||
// configurable boost deque performs much better than std::deque in our use cases
|
||||
using block_1024_option_t = boost::container::deque_options< boost::container::block_size<1024u> >::type;
|
||||
template<typename T>
|
||||
using deque = boost::container::deque< T, void, block_1024_option_t >;
|
||||
#else
|
||||
template<typename T>
|
||||
using deque = std::deque<T>;
|
||||
#endif
|
||||
|
||||
struct void_t{};
|
||||
|
||||
using chainbase::allocator;
|
||||
@@ -251,7 +241,6 @@ namespace eosio { namespace chain {
|
||||
using int128_t = __int128;
|
||||
using uint128_t = unsigned __int128;
|
||||
using bytes = vector<char>;
|
||||
using digests_t = deque<digest_type>;
|
||||
|
||||
struct sha256_less {
|
||||
bool operator()( const fc::sha256& lhs, const fc::sha256& rhs ) const {
|
||||
|
||||
@@ -32,12 +32,12 @@ using next_func_t = std::function<void(const std::variant<fc::exception_ptr, tra
|
||||
|
||||
struct unapplied_transaction {
|
||||
const transaction_metadata_ptr trx_meta;
|
||||
const fc::time_point expiry;
|
||||
trx_enum_type trx_type = trx_enum_type::unknown;
|
||||
bool return_failure_trace = false;
|
||||
next_func_t next;
|
||||
|
||||
const transaction_id_type& id()const { return trx_meta->id(); }
|
||||
fc::time_point_sec expiration()const { return trx_meta->packed_trx()->expiration(); }
|
||||
|
||||
unapplied_transaction(const unapplied_transaction&) = delete;
|
||||
unapplied_transaction() = delete;
|
||||
@@ -61,7 +61,7 @@ private:
|
||||
const_mem_fun<unapplied_transaction, const transaction_id_type&, &unapplied_transaction::id>
|
||||
>,
|
||||
ordered_non_unique< tag<by_type>, member<unapplied_transaction, trx_enum_type, &unapplied_transaction::trx_type> >,
|
||||
ordered_non_unique< tag<by_expiry>, const_mem_fun<unapplied_transaction, fc::time_point_sec, &unapplied_transaction::expiration> >
|
||||
ordered_non_unique< tag<by_expiry>, member<unapplied_transaction, const fc::time_point, &unapplied_transaction::expiry> >
|
||||
>
|
||||
> unapplied_trx_queue_type;
|
||||
|
||||
@@ -96,15 +96,15 @@ public:
|
||||
return itr->trx_meta;
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
bool clear_expired( const time_point& pending_block_time, const time_point& deadline, Func&& callback ) {
|
||||
template <typename Yield, typename Callback>
|
||||
bool clear_expired( const time_point& pending_block_time, Yield&& yield, Callback&& callback ) {
|
||||
auto& persisted_by_expiry = queue.get<by_expiry>();
|
||||
while( !persisted_by_expiry.empty() ) {
|
||||
const auto& itr = persisted_by_expiry.begin();
|
||||
if( itr->expiration() > pending_block_time ) {
|
||||
if( itr->expiry > pending_block_time ) {
|
||||
break;
|
||||
}
|
||||
if( deadline <= fc::time_point::now() ) {
|
||||
if( yield() ) {
|
||||
return false;
|
||||
}
|
||||
callback( itr->trx_meta->packed_trx(), itr->trx_type );
|
||||
@@ -146,15 +146,17 @@ public:
|
||||
const block_state_ptr& bsptr = *ritr;
|
||||
for( auto itr = bsptr->trxs_metas().begin(), end = bsptr->trxs_metas().end(); itr != end; ++itr ) {
|
||||
const auto& trx = *itr;
|
||||
auto insert_itr = queue.insert( { trx, trx_enum_type::forked } );
|
||||
fc::time_point expiry = trx->packed_trx()->expiration();
|
||||
auto insert_itr = queue.insert( { trx, expiry, trx_enum_type::forked } );
|
||||
if( insert_itr.second ) added( insert_itr.first );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void add_aborted( deque<transaction_metadata_ptr> aborted_trxs ) {
|
||||
void add_aborted( std::vector<transaction_metadata_ptr> aborted_trxs ) {
|
||||
for( auto& trx : aborted_trxs ) {
|
||||
auto insert_itr = queue.insert( { std::move( trx ), trx_enum_type::aborted } );
|
||||
fc::time_point expiry = trx->packed_trx()->expiration();
|
||||
auto insert_itr = queue.insert( { std::move( trx ), expiry, trx_enum_type::aborted } );
|
||||
if( insert_itr.second ) added( insert_itr.first );
|
||||
}
|
||||
}
|
||||
@@ -162,14 +164,14 @@ public:
|
||||
void add_persisted( const transaction_metadata_ptr& trx ) {
|
||||
auto itr = queue.get<by_trx_id>().find( trx->id() );
|
||||
if( itr == queue.get<by_trx_id>().end() ) {
|
||||
auto insert_itr = queue.insert( { trx, trx_enum_type::persisted } );
|
||||
fc::time_point expiry = trx->packed_trx()->expiration();
|
||||
auto insert_itr = queue.insert( { trx, expiry, trx_enum_type::persisted } );
|
||||
if( insert_itr.second ) added( insert_itr.first );
|
||||
} else if( itr->trx_type != trx_enum_type::persisted ) {
|
||||
if (itr->trx_type == trx_enum_type::incoming || itr->trx_type == trx_enum_type::incoming_persisted)
|
||||
--incoming_count;
|
||||
queue.get<by_trx_id>().modify( itr, [](auto& un){
|
||||
un.trx_type = trx_enum_type::persisted;
|
||||
un.next = nullptr; // persisted already have ack'ed initial trace
|
||||
} );
|
||||
}
|
||||
}
|
||||
@@ -177,8 +179,9 @@ public:
|
||||
void add_incoming( const transaction_metadata_ptr& trx, bool persist_until_expired, bool return_failure_trace, next_func_t next ) {
|
||||
auto itr = queue.get<by_trx_id>().find( trx->id() );
|
||||
if( itr == queue.get<by_trx_id>().end() ) {
|
||||
fc::time_point expiry = trx->packed_trx()->expiration();
|
||||
auto insert_itr = queue.insert(
|
||||
{ trx, persist_until_expired ? trx_enum_type::incoming_persisted : trx_enum_type::incoming, return_failure_trace, std::move( next ) } );
|
||||
{ trx, expiry, persist_until_expired ? trx_enum_type::incoming_persisted : trx_enum_type::incoming, return_failure_trace, std::move( next ) } );
|
||||
if( insert_itr.second ) added( insert_itr.first );
|
||||
} else {
|
||||
if( itr->trx_meta == trx ) return; // same trx meta pointer
|
||||
@@ -204,12 +207,6 @@ public:
|
||||
iterator incoming_begin() { return queue.get<by_type>().lower_bound( trx_enum_type::incoming_persisted ); }
|
||||
iterator incoming_end() { return queue.get<by_type>().end(); } // if changed to upper_bound, verify usage performance
|
||||
|
||||
iterator lower_bound( const transaction_id_type& id ) {
|
||||
auto itr = queue.get<by_trx_id>().find( id );
|
||||
if( itr == queue.get<by_trx_id>().end() ) return queue.get<by_type>().end();
|
||||
return queue.project<by_type>(itr);
|
||||
}
|
||||
|
||||
/// caller's responsibility to call next() if applicable
|
||||
iterator erase( iterator itr ) {
|
||||
removed( itr );
|
||||
|
||||
@@ -50,9 +50,7 @@ class memory {
|
||||
// The maximum amount of data that PIC code can include in the prologue
|
||||
static constexpr uintptr_t max_prologue_size = mutable_global_size + table_size;
|
||||
|
||||
// Changed from -cb_offset == EOS_VM_OC_CONTROL_BLOCK_OFFSET to get around
|
||||
// of compile warning about comparing integers of different signedness
|
||||
static_assert(EOS_VM_OC_CONTROL_BLOCK_OFFSET + cb_offset == 0, "EOS VM OC control block offset has slid out of place somehow");
|
||||
static_assert(-cb_offset == EOS_VM_OC_CONTROL_BLOCK_OFFSET, "EOS VM OC control block offset has slid out of place somehow");
|
||||
static_assert(stride == EOS_VM_OC_MEMORY_STRIDE, "EOS VM OC memory stride has slid out of place somehow");
|
||||
|
||||
private:
|
||||
|
||||
@@ -844,7 +844,7 @@ namespace webassembly {
|
||||
|
||||
/**
|
||||
* Find the table row in a primary 64-bit integer index table that matches the lowerbound condition for a given primary key.
|
||||
* Lowerbound record is the first nearest record which primary key is >= the given key.
|
||||
* Lowerbound record is the first nearest record which primary key is <= the given key.
|
||||
*
|
||||
* @ingroup database primary-index
|
||||
* @param code - the name of the owner of the table.
|
||||
@@ -954,7 +954,7 @@ namespace webassembly {
|
||||
|
||||
/**
|
||||
* Find the table row in a secondary 64-bit integer index table that matches the lowerbound condition for a given secondary key.
|
||||
* Lowerbound secondary index is the first secondary index which key is >= the given secondary index key.
|
||||
* Lowerbound secondary index is the first secondary index which key is <= the given secondary index key.
|
||||
*
|
||||
* @ingroup database uint64_t-secondary-index
|
||||
* @param code - the name of the owner of the table.
|
||||
@@ -1095,7 +1095,7 @@ namespace webassembly {
|
||||
|
||||
/**
|
||||
* Find the table row in a secondary 128-bit integer index table that matches the lowerbound condition for a given secondary key.
|
||||
* Lowerbound secondary index is the first secondary index which key is >= the given secondary index key.
|
||||
* Lowerbound secondary index is the first secondary index which key is <= the given secondary index key.
|
||||
*
|
||||
* @ingroup database uint128_t-secondary-index
|
||||
* @param code - the name of the owner of the table.
|
||||
@@ -1236,7 +1236,7 @@ namespace webassembly {
|
||||
|
||||
/**
|
||||
* Find the table row in a secondary 256-bit integer index table that matches the lowerbound condition for a given secondary key.
|
||||
* Lowerbound secondary index is the first secondary index which key is >= the given secondary index key.
|
||||
* Lowerbound secondary index is the first secondary index which key is <= the given secondary index key.
|
||||
*
|
||||
* @ingroup database 256-bit-secondary-index
|
||||
* @param code - the name of the owner of the table.
|
||||
@@ -1380,7 +1380,7 @@ namespace webassembly {
|
||||
|
||||
/**
|
||||
* Find the table row in a secondary double-precision floating-point index table that matches the lowerbound condition for a given secondary key.
|
||||
* Lowerbound secondary index is the first secondary index which key is >= the given secondary index key.
|
||||
* Lowerbound secondary index is the first secondary index which key is <= the given secondary index key.
|
||||
*
|
||||
* @ingroup database double-secondary-index
|
||||
* @param code - the name of the owner of the table.
|
||||
@@ -1524,7 +1524,7 @@ namespace webassembly {
|
||||
|
||||
/**
|
||||
* Find the table row in a secondary quadruple-precision floating-point index table that matches the lowerbound condition for a given secondary key.
|
||||
* Lowerbound secondary index is the first secondary index which key is >= the given secondary index key.
|
||||
* Lowerbound secondary index is the first secondary index which key is <= the given secondary index key.
|
||||
*
|
||||
* @ingroup database long-double-secondary-index
|
||||
* @param code - the name of the owner of the table.
|
||||
|
||||
@@ -32,7 +32,7 @@ bool is_canonical_right(const digest_type& val) {
|
||||
}
|
||||
|
||||
|
||||
digest_type merkle(deque<digest_type> ids) {
|
||||
digest_type merkle(vector<digest_type> ids) {
|
||||
if( 0 == ids.size() ) { return digest_type(); }
|
||||
|
||||
while( ids.size() > 1 ) {
|
||||
|
||||
@@ -28,7 +28,6 @@ platform_timer::platform_timer() {
|
||||
|
||||
if(refcount++ == 0) {
|
||||
std::promise<void> p;
|
||||
auto f = p.get_future();
|
||||
checktime_thread = std::thread([&p]() {
|
||||
fc::set_os_thread_name("checktime");
|
||||
checktime_ios = std::make_unique<boost::asio::io_service>();
|
||||
@@ -37,7 +36,7 @@ platform_timer::platform_timer() {
|
||||
|
||||
checktime_ios->run();
|
||||
});
|
||||
f.get();
|
||||
p.get_future().get();
|
||||
}
|
||||
|
||||
my->timer = std::make_unique<boost::asio::high_resolution_timer>(*checktime_ios);
|
||||
@@ -65,12 +64,11 @@ void platform_timer::start(fc::time_point tp) {
|
||||
else {
|
||||
#if 0
|
||||
std::promise<void> p;
|
||||
auto f = p.get_future();
|
||||
checktime_ios->post([&p,this]() {
|
||||
expired = 0;
|
||||
p.set_value();
|
||||
});
|
||||
f.get();
|
||||
p.get_future().get();
|
||||
#endif
|
||||
expired = 0;
|
||||
my->timer->expires_after(std::chrono::microseconds(x.count()));
|
||||
|
||||
@@ -418,8 +418,7 @@ std::pair<int64_t, bool> resource_limits_manager::get_account_cpu_limit( const a
|
||||
return {arl.available, greylisted};
|
||||
}
|
||||
|
||||
std::pair<account_resource_limit, bool>
|
||||
resource_limits_manager::get_account_cpu_limit_ex( const account_name& name, uint32_t greylist_limit, const std::optional<block_timestamp_type>& current_time) const {
|
||||
std::pair<account_resource_limit, bool> resource_limits_manager::get_account_cpu_limit_ex( const account_name& name, uint32_t greylist_limit ) const {
|
||||
|
||||
const auto& state = _db.get<resource_limits_state_object>();
|
||||
const auto& usage = _db.get<resource_usage_object, by_owner>(name);
|
||||
@@ -429,7 +428,7 @@ resource_limits_manager::get_account_cpu_limit_ex( const account_name& name, uin
|
||||
get_account_limits( name, x, y, cpu_weight );
|
||||
|
||||
if( cpu_weight < 0 || state.total_cpu_weight == 0 ) {
|
||||
return {{ -1, -1, -1, block_timestamp_type(usage.cpu_usage.last_ordinal), -1 }, false};
|
||||
return {{ -1, -1, -1 }, false};
|
||||
}
|
||||
|
||||
account_resource_limit arl;
|
||||
@@ -463,15 +462,6 @@ resource_limits_manager::get_account_cpu_limit_ex( const account_name& name, uin
|
||||
|
||||
arl.used = impl::downgrade_cast<int64_t>(cpu_used_in_window);
|
||||
arl.max = impl::downgrade_cast<int64_t>(max_user_use_in_window);
|
||||
arl.last_usage_update_time = block_timestamp_type(usage.cpu_usage.last_ordinal);
|
||||
arl.current_used = arl.used;
|
||||
if ( current_time ) {
|
||||
if (current_time->slot > usage.cpu_usage.last_ordinal) {
|
||||
auto history_usage = usage.cpu_usage;
|
||||
history_usage.add(0, current_time->slot, window_size);
|
||||
arl.current_used = impl::downgrade_cast<int64_t>(impl::integer_divide_ceil((uint128_t)history_usage.value_ex * window_size, (uint128_t)config::rate_limiting_precision));
|
||||
}
|
||||
}
|
||||
return {arl, greylisted};
|
||||
}
|
||||
|
||||
@@ -480,8 +470,7 @@ std::pair<int64_t, bool> resource_limits_manager::get_account_net_limit( const a
|
||||
return {arl.available, greylisted};
|
||||
}
|
||||
|
||||
std::pair<account_resource_limit, bool>
|
||||
resource_limits_manager::get_account_net_limit_ex( const account_name& name, uint32_t greylist_limit, const std::optional<block_timestamp_type>& current_time) const {
|
||||
std::pair<account_resource_limit, bool> resource_limits_manager::get_account_net_limit_ex( const account_name& name, uint32_t greylist_limit ) const {
|
||||
const auto& config = _db.get<resource_limits_config_object>();
|
||||
const auto& state = _db.get<resource_limits_state_object>();
|
||||
const auto& usage = _db.get<resource_usage_object, by_owner>(name);
|
||||
@@ -490,7 +479,7 @@ resource_limits_manager::get_account_net_limit_ex( const account_name& name, uin
|
||||
get_account_limits( name, x, net_weight, y );
|
||||
|
||||
if( net_weight < 0 || state.total_net_weight == 0) {
|
||||
return {{ -1, -1, -1, block_timestamp_type(usage.net_usage.last_ordinal), -1 }, false};
|
||||
return {{ -1, -1, -1 }, false};
|
||||
}
|
||||
|
||||
account_resource_limit arl;
|
||||
@@ -524,15 +513,6 @@ resource_limits_manager::get_account_net_limit_ex( const account_name& name, uin
|
||||
|
||||
arl.used = impl::downgrade_cast<int64_t>(net_used_in_window);
|
||||
arl.max = impl::downgrade_cast<int64_t>(max_user_use_in_window);
|
||||
arl.last_usage_update_time = block_timestamp_type(usage.net_usage.last_ordinal);
|
||||
arl.current_used = arl.used;
|
||||
if ( current_time ) {
|
||||
if (current_time->slot > usage.net_usage.last_ordinal) {
|
||||
auto history_usage = usage.net_usage;
|
||||
history_usage.add(0, current_time->slot, window_size);
|
||||
arl.current_used = impl::downgrade_cast<int64_t>(impl::integer_divide_ceil((uint128_t)history_usage.value_ex * window_size, (uint128_t)config::rate_limiting_precision));
|
||||
}
|
||||
}
|
||||
return {arl, greylisted};
|
||||
}
|
||||
|
||||
|
||||
+49
-134
@@ -1,16 +1,6 @@
|
||||
#define RAPIDJSON_NAMESPACE eosio_rapidjson // This is ABSOLUTELY necessary anywhere that is using eosio_rapidjson
|
||||
|
||||
#include <eosio/chain/snapshot.hpp>
|
||||
#include <eosio/chain/exceptions.hpp>
|
||||
#include <fc/scoped_exit.hpp>
|
||||
#include <fc/io/json.hpp>
|
||||
|
||||
#include <rapidjson/document.h>
|
||||
#include <rapidjson/filereadstream.h>
|
||||
#include <rapidjson/stringbuffer.h>
|
||||
#include <rapidjson/writer.h>
|
||||
|
||||
using namespace eosio_rapidjson;
|
||||
|
||||
namespace eosio { namespace chain {
|
||||
|
||||
@@ -86,6 +76,17 @@ void variant_snapshot_reader::validate() const {
|
||||
}
|
||||
}
|
||||
|
||||
bool variant_snapshot_reader::has_section( const string& section_name ) {
|
||||
const auto& sections = snapshot["sections"].get_array();
|
||||
for( const auto& section: sections ) {
|
||||
if (section["name"].as_string() == section_name) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void variant_snapshot_reader::set_section( const string& section_name ) {
|
||||
const auto& sections = snapshot["sections"].get_array();
|
||||
for( const auto& section: sections ) {
|
||||
@@ -189,45 +190,6 @@ void ostream_snapshot_writer::finalize() {
|
||||
snapshot.write((char*)&end_marker, sizeof(end_marker));
|
||||
}
|
||||
|
||||
ostream_json_snapshot_writer::ostream_json_snapshot_writer(std::ostream& snapshot)
|
||||
:snapshot(snapshot)
|
||||
,row_count(0)
|
||||
{
|
||||
snapshot << "{\n";
|
||||
// write magic number
|
||||
auto totem = magic_number;
|
||||
snapshot << "\"magic_number\":" << fc::json::to_string(totem, fc::time_point::maximum()) << "\n";
|
||||
|
||||
// write version
|
||||
auto version = current_snapshot_version;
|
||||
snapshot << ",\"version\":" << fc::json::to_string(version, fc::time_point::maximum()) << "\n";
|
||||
}
|
||||
|
||||
void ostream_json_snapshot_writer::write_start_section( const std::string& section_name )
|
||||
{
|
||||
row_count = 0;
|
||||
snapshot.inner << "," << fc::json::to_string(section_name, fc::time_point::maximum()) << ":{\n\"rows\":[\n";
|
||||
}
|
||||
|
||||
void ostream_json_snapshot_writer::write_row( const detail::abstract_snapshot_row_writer& row_writer ) {
|
||||
const auto yield = [&](size_t s) {};
|
||||
|
||||
if(row_count != 0) snapshot.inner << ",";
|
||||
snapshot.inner << fc::json::to_string(row_writer.to_variant(), yield) << "\n";
|
||||
++row_count;
|
||||
}
|
||||
|
||||
void ostream_json_snapshot_writer::write_end_section( ) {
|
||||
snapshot.inner << "],\n\"num_rows\":" << row_count << "\n}\n";
|
||||
row_count = 0;
|
||||
}
|
||||
|
||||
void ostream_json_snapshot_writer::finalize() {
|
||||
snapshot.inner << "}\n";
|
||||
snapshot.inner.flush();
|
||||
}
|
||||
|
||||
|
||||
istream_snapshot_reader::istream_snapshot_reader(std::istream& snapshot)
|
||||
:snapshot(snapshot)
|
||||
,header_pos(snapshot.tellg())
|
||||
@@ -284,6 +246,44 @@ bool istream_snapshot_reader::validate_section() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool istream_snapshot_reader::has_section( const string& section_name ) {
|
||||
auto restore_pos = fc::make_scoped_exit([this,pos=snapshot.tellg()](){
|
||||
snapshot.seekg(pos);
|
||||
});
|
||||
|
||||
const std::streamoff header_size = sizeof(ostream_snapshot_writer::magic_number) + sizeof(current_snapshot_version);
|
||||
|
||||
auto next_section_pos = header_pos + header_size;
|
||||
|
||||
while (true) {
|
||||
snapshot.seekg(next_section_pos);
|
||||
uint64_t section_size = 0;
|
||||
snapshot.read((char*)§ion_size,sizeof(section_size));
|
||||
if (section_size == std::numeric_limits<uint64_t>::max()) {
|
||||
break;
|
||||
}
|
||||
|
||||
next_section_pos = snapshot.tellg() + std::streamoff(section_size);
|
||||
|
||||
uint64_t ignore = 0;
|
||||
snapshot.read((char*)&ignore,sizeof(ignore));
|
||||
|
||||
bool match = true;
|
||||
for(auto c : section_name) {
|
||||
if(snapshot.get() != c) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (match && snapshot.get() == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void istream_snapshot_reader::set_section( const string& section_name ) {
|
||||
auto restore_pos = fc::make_scoped_exit([this,pos=snapshot.tellg()](){
|
||||
snapshot.seekg(pos);
|
||||
@@ -346,91 +346,6 @@ void istream_snapshot_reader::return_to_header() {
|
||||
clear_section();
|
||||
}
|
||||
|
||||
struct istream_json_snapshot_reader_impl {
|
||||
uint64_t num_rows;
|
||||
uint64_t cur_row;
|
||||
eosio_rapidjson::Document doc;
|
||||
std::string sec_name;
|
||||
};
|
||||
|
||||
istream_json_snapshot_reader::~istream_json_snapshot_reader() = default;
|
||||
|
||||
istream_json_snapshot_reader::istream_json_snapshot_reader(const fc::path& p)
|
||||
: impl{new istream_json_snapshot_reader_impl{0, 0, {}, {}}}
|
||||
{
|
||||
FILE* fp = fopen(p.string().c_str(), "rb");
|
||||
EOS_ASSERT(fp, snapshot_exception, "Failed to open JSON snapshot: ${file}", ("file", p));
|
||||
auto close = fc::make_scoped_exit( [&fp]() { fclose( fp ); } );
|
||||
char readBuffer[65536];
|
||||
eosio_rapidjson::FileReadStream is(fp, readBuffer, sizeof(readBuffer));
|
||||
impl->doc.ParseStream(is);
|
||||
}
|
||||
|
||||
void istream_json_snapshot_reader::validate() const {
|
||||
try {
|
||||
// validate totem
|
||||
auto expected_totem = ostream_json_snapshot_writer::magic_number;
|
||||
EOS_ASSERT(impl->doc.HasMember("magic_number"), snapshot_exception, "magic_number section not found" );
|
||||
auto actual_totem = impl->doc["magic_number"].GetUint();
|
||||
EOS_ASSERT( actual_totem == expected_totem, snapshot_exception, "JSON snapshot has unexpected magic number" );
|
||||
|
||||
// validate version
|
||||
auto expected_version = current_snapshot_version;
|
||||
EOS_ASSERT(impl->doc.HasMember("version"), snapshot_exception, "version section not found" );
|
||||
auto actual_version = impl->doc["version"].GetUint();
|
||||
EOS_ASSERT( actual_version == expected_version, snapshot_exception,
|
||||
"JSON snapshot is an unsupported version. Expected : ${expected}, Got: ${actual}",
|
||||
("expected", expected_version)( "actual", actual_version ) );
|
||||
|
||||
} catch( const std::exception& e ) { \
|
||||
snapshot_exception fce(FC_LOG_MESSAGE( warn, "JSON snapshot validation threw IO exception (${what})",("what",e.what())));
|
||||
throw fce;
|
||||
}
|
||||
}
|
||||
|
||||
bool istream_json_snapshot_reader::validate_section() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
void istream_json_snapshot_reader::set_section( const string& section_name ) {
|
||||
EOS_ASSERT( impl->doc.HasMember( section_name.c_str() ), snapshot_exception, "JSON snapshot has no section ${sec}", ("sec", section_name) );
|
||||
EOS_ASSERT( impl->doc[section_name.c_str()].HasMember( "num_rows" ), snapshot_exception, "JSON snapshot ${sec} num_rows not found", ("sec", section_name) );
|
||||
EOS_ASSERT( impl->doc[section_name.c_str()].HasMember( "rows" ), snapshot_exception, "JSON snapshot ${sec} rows not found", ("sec", section_name) );
|
||||
EOS_ASSERT( impl->doc[section_name.c_str()]["rows"].IsArray(), snapshot_exception, "JSON snapshot ${sec} rows is not an array", ("sec_name", section_name) );
|
||||
|
||||
impl->sec_name = section_name;
|
||||
impl->num_rows = impl->doc[section_name.c_str()]["num_rows"].GetInt();
|
||||
ilog( "reading ${section_name}, num_rows: ${num_rows}", ("section_name", section_name)( "num_rows", impl->num_rows ) );
|
||||
}
|
||||
|
||||
bool istream_json_snapshot_reader::read_row( detail::abstract_snapshot_row_reader& row_reader ) {
|
||||
EOS_ASSERT( impl->cur_row < impl->num_rows, snapshot_exception, "JSON snapshot ${sect}'s cur_row ${cur_row} >= num_rows ${num_rows}",
|
||||
("sect_name", impl->sec_name)( "cur_row", impl->cur_row )( "num_rows", impl->num_rows ) );
|
||||
|
||||
const eosio_rapidjson::Value& rows = impl->doc[impl->sec_name.c_str()]["rows"];
|
||||
eosio_rapidjson::StringBuffer buffer;
|
||||
eosio_rapidjson::Writer<eosio_rapidjson::StringBuffer> writer( buffer );
|
||||
rows[impl->cur_row].Accept( writer );
|
||||
|
||||
const auto& row = fc::json::from_string( buffer.GetString() );
|
||||
row_reader.provide( row );
|
||||
return ++impl->cur_row < impl->num_rows;
|
||||
}
|
||||
|
||||
bool istream_json_snapshot_reader::empty ( ) {
|
||||
return impl->num_rows == 0;
|
||||
}
|
||||
|
||||
void istream_json_snapshot_reader::clear_section() {
|
||||
impl->num_rows = 0;
|
||||
impl->cur_row = 0;
|
||||
impl->sec_name = "";
|
||||
}
|
||||
|
||||
void istream_json_snapshot_reader::return_to_header() {
|
||||
clear_section();
|
||||
}
|
||||
|
||||
integrity_hash_snapshot_writer::integrity_hash_snapshot_writer(fc::sha256::encoder& enc)
|
||||
:enc(enc)
|
||||
{
|
||||
|
||||
@@ -138,7 +138,7 @@ namespace eosio { namespace chain {
|
||||
initial_objective_duration_limit = objective_duration_limit;
|
||||
|
||||
if( explicit_billed_cpu_time )
|
||||
validate_cpu_usage_to_bill( billed_cpu_time_us, std::numeric_limits<int64_t>::max(), false, subjective_cpu_bill_us); // Fail early if the amount to be billed is too high
|
||||
validate_cpu_usage_to_bill( billed_cpu_time_us, std::numeric_limits<int64_t>::max(), false ); // Fail early if the amount to be billed is too high
|
||||
|
||||
// Record accounts to be billed for network and CPU usage
|
||||
if( control.is_builtin_activated(builtin_protocol_feature_t::only_bill_first_authorizer) ) {
|
||||
@@ -204,7 +204,7 @@ namespace eosio { namespace chain {
|
||||
if( validate_account_cpu_limit > 0 )
|
||||
validate_account_cpu_limit -= EOS_PERCENT( validate_account_cpu_limit, 10 * config::percent_1 );
|
||||
if( validate_account_cpu_limit < 0 ) validate_account_cpu_limit = 0;
|
||||
validate_account_cpu_usage_estimate( billed_cpu_time_us, validate_account_cpu_limit, subjective_cpu_bill_us );
|
||||
validate_account_cpu_usage_estimate( billed_cpu_time_us, validate_account_cpu_limit );
|
||||
}
|
||||
|
||||
eager_net_limit = (eager_net_limit/8)*8; // Round down to nearest multiple of word size (8 bytes) so check_net_usage can be efficient
|
||||
@@ -368,7 +368,7 @@ namespace eosio { namespace chain {
|
||||
|
||||
update_billed_cpu_time( now );
|
||||
|
||||
validate_cpu_usage_to_bill( billed_cpu_time_us, account_cpu_limit, true, subjective_cpu_bill_us );
|
||||
validate_cpu_usage_to_bill( billed_cpu_time_us, account_cpu_limit, true );
|
||||
|
||||
rl.add_transaction_usage( bill_to_accounts, static_cast<uint64_t>(billed_cpu_time_us), net_usage,
|
||||
block_timestamp_type(control.pending_block_time()).slot ); // Should never fail
|
||||
@@ -415,19 +415,14 @@ namespace eosio { namespace chain {
|
||||
"not enough time left in block to complete executing transaction ${billing_timer}us",
|
||||
("now", now)("deadline", _deadline)("start", start)("billing_timer", now - pseudo_start) );
|
||||
} else if( deadline_exception_code == tx_cpu_usage_exceeded::code_value ) {
|
||||
std::string assert_msg = "transaction was executing for too long ${billing_timer}us";
|
||||
if (subjective_cpu_bill_us > 0) {
|
||||
assert_msg += " with a subjective cpu of (${subjective} us)";
|
||||
}
|
||||
if (cpu_limit_due_to_greylist) {
|
||||
assert_msg = "greylisted " + assert_msg;
|
||||
EOS_THROW( greylist_cpu_usage_exceeded,
|
||||
assert_msg,
|
||||
("now", now)("deadline", _deadline)("start", start)("billing_timer", now - pseudo_start)( "subjective", subjective_cpu_bill_us) );
|
||||
"greylisted transaction was executing for too long ${billing_timer}us",
|
||||
("now", now)("deadline", _deadline)("start", start)("billing_timer", now - pseudo_start) );
|
||||
} else {
|
||||
EOS_THROW( tx_cpu_usage_exceeded,
|
||||
assert_msg,
|
||||
("now", now)("deadline", _deadline)("start", start)("billing_timer", now - pseudo_start)("subjective", subjective_cpu_bill_us) );
|
||||
"transaction was executing for too long ${billing_timer}us",
|
||||
("now", now)("deadline", _deadline)("start", start)("billing_timer", now - pseudo_start) );
|
||||
}
|
||||
} else if( deadline_exception_code == leeway_deadline_exception::code_value ) {
|
||||
EOS_THROW( leeway_deadline_exception,
|
||||
@@ -465,7 +460,7 @@ namespace eosio { namespace chain {
|
||||
transaction_timer.start(_deadline);
|
||||
}
|
||||
|
||||
void transaction_context::validate_cpu_usage_to_bill( int64_t billed_us, int64_t account_cpu_limit, bool check_minimum, int64_t subjective_billed_us )const {
|
||||
void transaction_context::validate_cpu_usage_to_bill( int64_t billed_us, int64_t account_cpu_limit, bool check_minimum )const {
|
||||
if (!control.skip_trx_checks()) {
|
||||
if( check_minimum ) {
|
||||
const auto& cfg = control.get_global_properties().configuration;
|
||||
@@ -475,11 +470,11 @@ namespace eosio { namespace chain {
|
||||
);
|
||||
}
|
||||
|
||||
validate_account_cpu_usage( billed_us, account_cpu_limit, subjective_billed_us );
|
||||
validate_account_cpu_usage( billed_us, account_cpu_limit );
|
||||
}
|
||||
}
|
||||
|
||||
void transaction_context::validate_account_cpu_usage( int64_t billed_us, int64_t account_cpu_limit, int64_t subjective_billed_us )const {
|
||||
void transaction_context::validate_account_cpu_usage( int64_t billed_us, int64_t account_cpu_limit )const {
|
||||
if( (billed_us > 0) && !control.skip_trx_checks() ) {
|
||||
const bool cpu_limited_by_account = (account_cpu_limit <= objective_duration_limit.count());
|
||||
|
||||
@@ -490,33 +485,26 @@ namespace eosio { namespace chain {
|
||||
("billed", billed_us)( "billable", objective_duration_limit.count() )
|
||||
);
|
||||
} else {
|
||||
auto assert_msg = [&](bool graylisted, bool subjective) {
|
||||
std::string assert_msg = "billed CPU time (${billed} us) is greater than the maximum";
|
||||
assert_msg += graylisted ? " greylisted" : "";
|
||||
assert_msg += " billable CPU time for the transaction (${billable} us)";
|
||||
assert_msg += subjective ? " with a subjective cpu of (${subjective} us)" : "";
|
||||
return assert_msg;
|
||||
};
|
||||
auto graylisted = cpu_limit_due_to_greylist && cpu_limited_by_account;
|
||||
auto subjective = subjective_billed_us > 0;
|
||||
// exceeds trx.max_cpu_usage_ms or cfg.max_transaction_cpu_usage if objective_duration_limit is greater
|
||||
auto limit = graylisted ? account_cpu_limit : (cpu_limited_by_account ? account_cpu_limit : objective_duration_limit.count());
|
||||
|
||||
if (graylisted)
|
||||
EOS_ASSERT( billed_us <= limit,
|
||||
greylist_cpu_usage_exceeded,
|
||||
assert_msg(graylisted, subjective),
|
||||
("billed", billed_us)("billable", limit)("subjective", subjective_billed_us));
|
||||
else
|
||||
EOS_ASSERT( billed_us <= limit,
|
||||
if( cpu_limit_due_to_greylist && cpu_limited_by_account ) {
|
||||
EOS_ASSERT( billed_us <= account_cpu_limit,
|
||||
greylist_cpu_usage_exceeded,
|
||||
"billed CPU time (${billed} us) is greater than the maximum greylisted billable CPU time for the transaction (${billable} us)",
|
||||
("billed", billed_us)( "billable", account_cpu_limit )
|
||||
);
|
||||
} else {
|
||||
// exceeds trx.max_cpu_usage_ms or cfg.max_transaction_cpu_usage if objective_duration_limit is greater
|
||||
const int64_t cpu_limit = (cpu_limited_by_account ? account_cpu_limit : objective_duration_limit.count());
|
||||
EOS_ASSERT( billed_us <= cpu_limit,
|
||||
tx_cpu_usage_exceeded,
|
||||
assert_msg(graylisted, subjective),
|
||||
("billed", billed_us)("billable", limit)("subjective", subjective_billed_us));
|
||||
"billed CPU time (${billed} us) is greater than the maximum billable CPU time for the transaction (${billable} us)",
|
||||
("billed", billed_us)( "billable", cpu_limit )
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void transaction_context::validate_account_cpu_usage_estimate( int64_t prev_billed_us, int64_t account_cpu_limit, int64_t subjective_billed_us )const {
|
||||
void transaction_context::validate_account_cpu_usage_estimate( int64_t prev_billed_us, int64_t account_cpu_limit )const {
|
||||
// prev_billed_us can be 0, but so can account_cpu_limit
|
||||
if( (prev_billed_us >= 0) && !control.skip_trx_checks() ) {
|
||||
const bool cpu_limited_by_account = (account_cpu_limit <= objective_duration_limit.count());
|
||||
@@ -528,28 +516,21 @@ namespace eosio { namespace chain {
|
||||
("billed", prev_billed_us)( "billable", objective_duration_limit.count() )
|
||||
);
|
||||
} else {
|
||||
auto assert_msg = [&](bool graylisted, bool subjective) {
|
||||
std::string assert_msg = "estimated CPU time (${billed} us) is not less than the maximum";
|
||||
assert_msg += graylisted ? " greylisted" : "";
|
||||
assert_msg += " billable CPU time for the transaction (${billable} us)";
|
||||
assert_msg += subjective ? " with a subjective cpu of (${subjective} us)" : "";
|
||||
return assert_msg;
|
||||
};
|
||||
auto graylisted = cpu_limit_due_to_greylist && cpu_limited_by_account;
|
||||
auto subjective = subjective_billed_us > 0;
|
||||
// exceeds trx.max_cpu_usage_ms or cfg.max_transaction_cpu_usage if objective_duration_limit is greater
|
||||
auto limit = graylisted ? account_cpu_limit : (cpu_limited_by_account ? account_cpu_limit : objective_duration_limit.count());
|
||||
|
||||
if (graylisted)
|
||||
EOS_ASSERT( prev_billed_us < limit,
|
||||
greylist_cpu_usage_exceeded,
|
||||
assert_msg(graylisted, subjective),
|
||||
("billed", prev_billed_us)("billable", limit)("subjective", subjective_billed_us));
|
||||
else
|
||||
EOS_ASSERT( prev_billed_us < limit,
|
||||
if( cpu_limit_due_to_greylist && cpu_limited_by_account ) {
|
||||
EOS_ASSERT( prev_billed_us < account_cpu_limit,
|
||||
greylist_cpu_usage_exceeded,
|
||||
"estimated CPU time (${billed} us) is not less than the maximum greylisted billable CPU time for the transaction (${billable} us)",
|
||||
("billed", prev_billed_us)( "billable", account_cpu_limit )
|
||||
);
|
||||
} else {
|
||||
// exceeds trx.max_cpu_usage_ms or cfg.max_transaction_cpu_usage if objective_duration_limit is greater
|
||||
const int64_t cpu_limit = (cpu_limited_by_account ? account_cpu_limit : objective_duration_limit.count());
|
||||
EOS_ASSERT( prev_billed_us < cpu_limit,
|
||||
tx_cpu_usage_exceeded,
|
||||
assert_msg(graylisted, subjective),
|
||||
("billed", prev_billed_us)("billable", limit)("subjective", subjective_billed_us));
|
||||
"estimated CPU time (${billed} us) is not less than the maximum billable CPU time for the transaction (${billable} us)",
|
||||
("billed", prev_billed_us)( "billable", cpu_limit )
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -740,14 +721,12 @@ namespace eosio { namespace chain {
|
||||
const auto& db = control.db();
|
||||
const auto& auth_manager = control.get_authorization_manager();
|
||||
|
||||
if( !trx.context_free_actions.empty() && !control.skip_trx_checks() ) {
|
||||
for( const auto& a : trx.context_free_actions ) {
|
||||
auto* code = db.find<account_object, by_name>( a.account );
|
||||
EOS_ASSERT( code != nullptr, transaction_exception,
|
||||
"action's code account '${account}' does not exist", ("account", a.account) );
|
||||
EOS_ASSERT( a.authorization.size() == 0, transaction_exception,
|
||||
"context-free actions cannot have authorizations" );
|
||||
}
|
||||
for( const auto& a : trx.context_free_actions ) {
|
||||
auto* code = db.find<account_object, by_name>(a.account);
|
||||
EOS_ASSERT( code != nullptr, transaction_exception,
|
||||
"action's code account '${account}' does not exist", ("account", a.account) );
|
||||
EOS_ASSERT( a.authorization.size() == 0, transaction_exception,
|
||||
"context-free actions cannot have authorizations" );
|
||||
}
|
||||
|
||||
flat_set<account_name> actors;
|
||||
|
||||
@@ -223,7 +223,7 @@ void executor::execute(const code_descriptor& code, memory& mem, apply_context&
|
||||
cb->bounce_buffers->clear();
|
||||
tt.set_expiration_callback(nullptr, nullptr);
|
||||
|
||||
int64_t base_pages = mem.size_of_memory_slice_mapping()/memory::stride - 1;
|
||||
uint64_t base_pages = mem.size_of_memory_slice_mapping()/memory::stride - 1;
|
||||
if(cb->current_linear_memory_pages > base_pages) {
|
||||
mprotect(mem.full_page_memory_base() + base_pages * eosio::chain::wasm_constraints::wasm_page_size,
|
||||
(cb->current_linear_memory_pages - base_pages) * eosio::chain::wasm_constraints::wasm_page_size, PROT_NONE);
|
||||
|
||||
@@ -25,7 +25,7 @@ memory::memory(uint64_t max_pages) {
|
||||
FC_ASSERT(mapbase != MAP_FAILED, "Failed to mmap memory");
|
||||
|
||||
uint8_t* next_slice = mapbase;
|
||||
uint8_t* last = nullptr;
|
||||
uint8_t* last;
|
||||
|
||||
for(unsigned int p = 0; p < number_slices; ++p) {
|
||||
last = (uint8_t*)mmap(next_slice, memory_prologue_size+64u*1024u*p, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, fd, 0);
|
||||
@@ -33,7 +33,6 @@ memory::memory(uint64_t max_pages) {
|
||||
next_slice += total_memory_per_slice;
|
||||
}
|
||||
|
||||
FC_ASSERT(last != nullptr, "expected last not nullptr");
|
||||
zeropage_base = mapbase + memory_prologue_size;
|
||||
fullpage_base = last + memory_prologue_size;
|
||||
|
||||
|
||||
@@ -247,7 +247,7 @@ std::unique_ptr<wasm_instantiated_module_interface> eos_vm_runtime<Impl>::instan
|
||||
wasm_code_ptr code((uint8_t*)code_bytes, code_size);
|
||||
apply_options options = { .max_pages = 65536,
|
||||
.max_call_depth = 0 };
|
||||
std::unique_ptr<backend_t> bkend = std::make_unique<backend_t>(code, code_size, nullptr, options);
|
||||
std::unique_ptr<backend_t> bkend = std::make_unique<backend_t>(code, code_size, nullptr, options, false); // uses 2-passes parsing
|
||||
eos_vm_host_functions_t::resolve(bkend->get_module());
|
||||
return std::make_unique<eos_vm_instantiated_module<Impl>>(this, std::move(bkend));
|
||||
} catch(eosio::vm::exception& e) {
|
||||
@@ -273,7 +273,7 @@ std::unique_ptr<wasm_instantiated_module_interface> eos_vm_profile_runtime::inst
|
||||
wasm_code_ptr code((uint8_t*)code_bytes, code_size);
|
||||
apply_options options = { .max_pages = 65536,
|
||||
.max_call_depth = 0 };
|
||||
std::unique_ptr<backend_t> bkend = std::make_unique<backend_t>(code, code_size, nullptr, options);
|
||||
std::unique_ptr<backend_t> bkend = std::make_unique<backend_t>(code, code_size, nullptr, options, false); // uses 2-passes parsing
|
||||
eos_vm_host_functions_t::resolve(bkend->get_module());
|
||||
return std::make_unique<eos_vm_profiling_module>(std::move(bkend), code_bytes, code_size);
|
||||
} catch(eosio::vm::exception& e) {
|
||||
|
||||
+1
-1
Submodule libraries/chainbase updated: 62d3f99059...dcd2a34391
@@ -1,2 +0,0 @@
|
||||
add_library(leap-cli11 INTERFACE)
|
||||
target_include_directories(leap-cli11 INTERFACE include)
|
||||
@@ -1,26 +0,0 @@
|
||||
|
||||
## instructions for building custom leap-cli11 library
|
||||
|
||||
leap-cli11 interface only library created in order to simplify integration of modified version of command line parsing library cli11
|
||||
|
||||
to update included in this library include/cli11/CLI11.hpp file it needs to be (re)geenerated from repository containing forked/modified version of it, in particular:
|
||||
|
||||
|
||||
```bash
|
||||
git clone https://github.com/AntelopeIO/CLI11.git
|
||||
cd CLI11
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DCLI11_SINGLE_FILE=ON ..
|
||||
make -j
|
||||
```
|
||||
|
||||
Resulting single-header will be located in:
|
||||
|
||||
```cpp
|
||||
build/include/CLI11.hpp
|
||||
```
|
||||
|
||||
And is ready to be copied to include/cli11/CLI11.hpp of leap-cli11 library
|
||||
|
||||
Automated CLI11 subproject build / import of CLI11.hpp header will be added in future versions.
|
||||
@@ -1,26 +0,0 @@
|
||||
#/usr/bin/env bash
|
||||
|
||||
_cleos_complete()
|
||||
{
|
||||
# Get cmdline while ignoring the last word
|
||||
cmdline=${COMP_LINE}
|
||||
if [[ "${cmdline:(-1)}" != " " ]]; then
|
||||
cmdline=${COMP_WORDS[@]:0:${COMP_CWORD}}
|
||||
fi
|
||||
|
||||
# Get complete candidates
|
||||
words=$(${cmdline} --_autocomplete "${COMP_WORDS[${COMP_CWORD}]}")
|
||||
|
||||
# Remove candidates that begins with `-` if `-` is not passed as the first character
|
||||
# TODO: move this logic inside CLI11? including the compgen?
|
||||
if [[ ! ${COMP_WORDS[${COMP_CWORD}]} = -* ]]; then
|
||||
words=(${words})
|
||||
for index in "${!words[@]}" ; do [[ ${words[$index]} =~ ^- ]] && unset -v 'words[$index]' ; done
|
||||
words="${words[@]}"
|
||||
fi
|
||||
|
||||
# Get matches
|
||||
COMPREPLY=($(compgen -W "${words}" -- "${COMP_WORDS[${COMP_CWORD}]}"))
|
||||
}
|
||||
|
||||
complete -F _cleos_complete cleos
|
||||
@@ -1,26 +0,0 @@
|
||||
#/usr/bin/env bash
|
||||
|
||||
_leap_complete()
|
||||
{
|
||||
# Get cmdline while ignoring the last word
|
||||
cmdline=${COMP_LINE}
|
||||
if [[ "${cmdline:(-1)}" != " " ]]; then
|
||||
cmdline=${COMP_WORDS[@]:0:${COMP_CWORD}}
|
||||
fi
|
||||
|
||||
# Get complete candidates
|
||||
words=$(${cmdline} --_autocomplete "${COMP_WORDS[${COMP_CWORD}]}")
|
||||
|
||||
# Remove candidates that begins with `-` if `-` is not passed as the first character
|
||||
# TODO: move this logic inside CLI11? including the compgen?
|
||||
if [[ ! ${COMP_WORDS[${COMP_CWORD}]} = -* ]]; then
|
||||
words=(${words})
|
||||
for index in "${!words[@]}" ; do [[ ${words[$index]} =~ ^- ]] && unset -v 'words[$index]' ; done
|
||||
words="${words[@]}"
|
||||
fi
|
||||
|
||||
# Get matches
|
||||
COMPREPLY=($(compgen -W "${words}" -- "${COMP_WORDS[${COMP_CWORD}]}"))
|
||||
}
|
||||
|
||||
complete -F _leap_complete leap-util
|
||||
+1
-1
Submodule libraries/eos-vm updated: 7db4b33fa9...4da112c820
Submodule
+1
Submodule libraries/fc added at 35144b5563
@@ -1,155 +0,0 @@
|
||||
add_subdirectory( secp256k1 )
|
||||
|
||||
set( WITH_PROCPS OFF CACHE BOOL "" FORCE)
|
||||
set( CURVE "ALT_BN128" CACHE STRING "" FORCE)
|
||||
set( USE_ASM OFF CACHE BOOL "" FORCE)
|
||||
set( IS_LIBFF_PARENT OFF CACHE BOOL "" FORCE)
|
||||
set( FF_INSTALL_COMPONENT "${FC_INSTALL_COMPONENT}")
|
||||
add_subdirectory( libraries/ff )
|
||||
|
||||
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
|
||||
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
|
||||
find_package(Threads)
|
||||
|
||||
find_package(OpenSSL REQUIRED)
|
||||
|
||||
set( fc_sources
|
||||
src/uint128.cpp
|
||||
src/real128.cpp
|
||||
src/variant.cpp
|
||||
src/exception.cpp
|
||||
src/variant_object.cpp
|
||||
src/string.cpp
|
||||
src/time.cpp
|
||||
src/mock_time.cpp
|
||||
src/utf8.cpp
|
||||
src/io/datastream.cpp
|
||||
src/io/json.cpp
|
||||
src/io/varint.cpp
|
||||
src/io/fstream.cpp
|
||||
src/io/console.cpp
|
||||
src/filesystem.cpp
|
||||
src/interprocess/file_mapping.cpp
|
||||
src/interprocess/mmap_struct.cpp
|
||||
src/log/log_message.cpp
|
||||
src/log/logger.cpp
|
||||
src/log/appender.cpp
|
||||
src/log/console_appender.cpp
|
||||
src/log/dmlog_appender.cpp
|
||||
src/log/logger_config.cpp
|
||||
src/crypto/_digest_common.cpp
|
||||
src/crypto/aes.cpp
|
||||
src/crypto/crc.cpp
|
||||
src/crypto/city.cpp
|
||||
# src/crypto/base32.cpp
|
||||
src/crypto/base36.cpp
|
||||
src/crypto/base58.cpp
|
||||
src/crypto/base64.cpp
|
||||
src/crypto/bigint.cpp
|
||||
src/crypto/hex.cpp
|
||||
src/crypto/sha1.cpp
|
||||
src/crypto/sha3.cpp
|
||||
src/crypto/ripemd160.cpp
|
||||
src/crypto/sha256.cpp
|
||||
src/crypto/sha224.cpp
|
||||
src/crypto/sha512.cpp
|
||||
src/crypto/dh.cpp
|
||||
src/crypto/blowfish.cpp
|
||||
src/crypto/elliptic_common.cpp
|
||||
src/crypto/elliptic_impl_priv.cpp
|
||||
src/crypto/elliptic_secp256k1.cpp
|
||||
src/crypto/elliptic_r1.cpp
|
||||
src/crypto/elliptic_webauthn.cpp
|
||||
src/crypto/rand.cpp
|
||||
src/crypto/public_key.cpp
|
||||
src/crypto/private_key.cpp
|
||||
src/crypto/signature.cpp
|
||||
src/crypto/alt_bn128.cpp
|
||||
src/crypto/modular_arithmetic.cpp
|
||||
src/crypto/blake2.cpp
|
||||
src/crypto/k1_recover.cpp
|
||||
src/network/ip.cpp
|
||||
src/network/platform_root_ca.cpp
|
||||
src/network/resolve.cpp
|
||||
src/network/udp_socket.cpp
|
||||
src/network/url.cpp
|
||||
src/network/http/http_client.cpp
|
||||
src/compress/smaz.cpp
|
||||
src/compress/zlib.cpp
|
||||
src/log/gelf_appender.cpp
|
||||
src/log/zipkin.cpp
|
||||
)
|
||||
|
||||
file( GLOB_RECURSE fc_headers ${CMAKE_CURRENT_SOURCE_DIR} *.hpp *.h )
|
||||
|
||||
add_library(fc ${fc_sources} ${fc_headers})
|
||||
|
||||
function(detect_thread_name)
|
||||
include(CheckSymbolExists)
|
||||
list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE)
|
||||
list(APPEND CMAKE_REQUIRED_LIBRARIES "-pthread")
|
||||
check_symbol_exists(pthread_setname_np pthread.h HAVE_PTHREAD_SETNAME_NP)
|
||||
if(HAVE_PTHREAD_SETNAME_NP)
|
||||
set_source_files_properties(src/log/logger_config.cpp PROPERTIES COMPILE_DEFINITIONS FC_USE_PTHREAD_NAME_NP)
|
||||
endif()
|
||||
endfunction()
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
detect_thread_name()
|
||||
endif()
|
||||
|
||||
# Yuck: newer CMake files from boost iostreams will effectively target_link_libraries(Boost::iostreams z;bz2;lzma;zstd)
|
||||
# without first "finding" those libraries. This resolves to simple -lz -lbz2 etc: it'll look for those libraries in the linker's
|
||||
# library search path. This is most problematic on macOS where something like libzstd isn't in the standard search path. Historically
|
||||
# fc would just "-L/usr/local/lib" as a heavy handed way to make sure something like -lzstd can be found in brew's library path. But
|
||||
# that isn't sufficient for something like ARM homebrew. Let's just "null" these libraries out since we're already linking to zlib
|
||||
# explicitly anyways via a proper find_package(ZLIB) below.
|
||||
if(APPLE)
|
||||
add_library(z INTERFACE)
|
||||
add_library(bz2 INTERFACE)
|
||||
add_library(lzma INTERFACE)
|
||||
add_library(zstd INTERFACE)
|
||||
endif()
|
||||
|
||||
find_package(Boost 1.66 REQUIRED COMPONENTS
|
||||
date_time
|
||||
filesystem
|
||||
chrono
|
||||
unit_test_framework
|
||||
iostreams)
|
||||
|
||||
# fc picks up a dependency on zlib via Boost::iostreams, however in some versions of cmake/boost (depending on if CMake config
|
||||
# files are used) the Boost::iostreams target does not have a dependency on zlib itself so add it explicitly
|
||||
find_package(ZLIB REQUIRED)
|
||||
|
||||
target_include_directories(fc PUBLIC include)
|
||||
|
||||
# try and make this very clear that this json parser is intended only for webauthn parsing..
|
||||
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.11.0)
|
||||
set_source_files_properties(src/crypto/elliptic_webauthn.cpp PROPERTIES INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/include/fc/crypto/webauthn_json/include")
|
||||
else()
|
||||
set_source_files_properties(src/crypto/elliptic_webauthn.cpp PROPERTIES COMPILE_FLAGS "-I${CMAKE_CURRENT_SOURCE_DIR}/include/fc/crypto/webauthn_json/include")
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries( fc PUBLIC ws2_32 mswsock userenv )
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
find_library(security_framework Security)
|
||||
find_library(corefoundation_framework CoreFoundation)
|
||||
endif()
|
||||
target_link_libraries( fc PUBLIC ff
|
||||
Boost::date_time Boost::filesystem Boost::chrono Boost::iostreams Threads::Threads
|
||||
OpenSSL::Crypto OpenSSL::SSL ZLIB::ZLIB ${PLATFORM_SPECIFIC_LIBS} ${CMAKE_DL_LIBS} secp256k1 ${security_framework} ${corefoundation_framework} )
|
||||
|
||||
# Critically, this ensures that OpenSSL 1.1 & 3.0 both have a variant of BN_zero() with void return value. But it also allows access
|
||||
# to some obsoleted AES functions in 3.0 too, since 3.0's API_COMPAT is effectively 3.0 by default
|
||||
target_compile_definitions(fc PUBLIC "OPENSSL_API_COMPAT=0x10100000L" "OPENSSL_NO_DEPRECATED")
|
||||
|
||||
add_subdirectory( test )
|
||||
|
||||
install(TARGETS fc
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} COMPONENT dev EXCLUDE_FROM_ALL
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} COMPONENT dev EXCLUDE_FROM_ALL)
|
||||
install(DIRECTORY include/fc DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR} COMPONENT dev EXCLUDE_FROM_ALL)
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
#pragma once
|
||||
#include <fc/api.hpp>
|
||||
#include <fc/thread/thread.hpp>
|
||||
|
||||
namespace fc {
|
||||
|
||||
namespace detail {
|
||||
struct actor_member {
|
||||
#if 1 // BOOST_NO_VARIADIC_TEMPLATES
|
||||
#define RPC_MEMBER_FUNCTOR(z,n,IS_CONST) \
|
||||
template<typename R, typename C, typename P BOOST_PP_ENUM_TRAILING_PARAMS( n, typename A)> \
|
||||
static std::function<fc::future<R>( BOOST_PP_ENUM_PARAMS(n,A) ) > \
|
||||
functor( P p, R (C::*mem_func)(BOOST_PP_ENUM_PARAMS(n,A)) IS_CONST, fc::thread* c = 0) { \
|
||||
return [=](BOOST_PP_ENUM_BINARY_PARAMS(n,A,a))->fc::future<R>{ \
|
||||
return c->async( [=](){ return (p->*mem_func)(BOOST_PP_ENUM_PARAMS(n,a)); } ); }; \
|
||||
}
|
||||
BOOST_PP_REPEAT( 8, RPC_MEMBER_FUNCTOR, const )
|
||||
BOOST_PP_REPEAT( 8, RPC_MEMBER_FUNCTOR, BOOST_PP_EMPTY() )
|
||||
#undef RPC_MEMBER_FUNCTOR
|
||||
|
||||
#else // g++ has a bug that prevents lambdas and varidic templates from working together (G++ Bug 41933)
|
||||
|
||||
template<typename R, typename C, typename P, typename... Args>
|
||||
static std::function<fc::future<R>(Args...)> functor( P&& p, R (C::*mem_func)(Args...), fc::thread* c ) {
|
||||
return [=](Args... args)->fc::future<R>{ c->async( [=]()->R { return p->*mem_func( fc::forward<Args>(args)... ); } ) };
|
||||
}
|
||||
template<typename R, typename C, typename P, typename... Args>
|
||||
static std::function<fc::future<R>(Args...)> functor( P&& p, R (C::*mem_func)(Args...)const, fc::thread* c ){
|
||||
return [=](Args... args)->fc::future<R>{ c->async( [=]()->R { return p->*mem_func( fc::forward<Args>(args)... ); } ) };
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template<typename ThisPtr>
|
||||
struct actor_vtable_visitor {
|
||||
template<typename U>
|
||||
actor_vtable_visitor( fc::thread* t, U&& u ):_thread(t),_this( fc::forward<U>(u) ){}
|
||||
|
||||
template<typename Function, typename MemberPtr>
|
||||
void operator()( const char* name, Function& memb, MemberPtr m )const {
|
||||
memb = actor_member::functor( _this, m, _thread );
|
||||
}
|
||||
fc::thread* _thread;
|
||||
ThisPtr _this;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Posts all method calls to another thread and
|
||||
* returns a future.
|
||||
*/
|
||||
template<typename Interface>
|
||||
class actor : public api<Interface, detail::actor_member> {
|
||||
public:
|
||||
actor(){}
|
||||
|
||||
template<typename InterfaceType>
|
||||
actor( InterfaceType* p, fc::thread* t = &fc::thread::current() )
|
||||
{
|
||||
this->_vtable.reset(new detail::vtable<Interface,detail::actor_member>() );
|
||||
this->_vtable->template visit<InterfaceType>( detail::actor_vtable_visitor<InterfaceType*>(t, p) );
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace fc
|
||||
@@ -1,14 +0,0 @@
|
||||
#pragma once
|
||||
namespace fc {
|
||||
|
||||
template<unsigned int S, typename T=double>
|
||||
struct aligned {
|
||||
union {
|
||||
T _align;
|
||||
char _data[S];
|
||||
} _store;
|
||||
operator char*() { return _store._data; }
|
||||
operator const char*()const { return _store._data; }
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
#pragma once
|
||||
#include <boost/any.hpp>
|
||||
|
||||
namespace fc {
|
||||
// TODO: define this without using boost
|
||||
typedef boost::any any;
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
#pragma once
|
||||
#include <fc/thread/future.hpp>
|
||||
#include <fc/any.hpp>
|
||||
#include <functional>
|
||||
#include <boost/config.hpp>
|
||||
|
||||
// ms visual c++ (as of 2013) doesn't accept the standard syntax for calling a
|
||||
// templated member function (foo->template bar();)
|
||||
#ifdef _MSC_VER
|
||||
# define FC_CALL_MEMBER_TEMPLATE_KEYWORD
|
||||
#else
|
||||
# define FC_CALL_MEMBER_TEMPLATE_KEYWORD template
|
||||
#endif
|
||||
|
||||
namespace fc {
|
||||
struct identity_member {
|
||||
template<typename R, typename C, typename P, typename... Args>
|
||||
static std::function<R(Args...)> functor( P&& p, R (C::*mem_func)(Args...) );
|
||||
template<typename R, typename C, typename P, typename... Args>
|
||||
static std::function<R(Args...)> functor( P&& p, R (C::*mem_func)(Args...)const );
|
||||
};
|
||||
|
||||
template< typename Interface, typename Transform >
|
||||
struct vtable : public std::enable_shared_from_this<vtable<Interface,Transform>>
|
||||
{ private: vtable(); };
|
||||
|
||||
template<typename OtherType>
|
||||
struct vtable_copy_visitor {
|
||||
typedef OtherType other_type;
|
||||
|
||||
vtable_copy_visitor( OtherType& s):_source( s ){}
|
||||
|
||||
template<typename R, typename MemberPtr, typename... Args>
|
||||
void operator()( const char* name, std::function<R(Args...)>& memb, MemberPtr m )const {
|
||||
OtherType* src = &_source;
|
||||
memb = [src,m]( Args... args ){ return (src->*m)(args...); };
|
||||
}
|
||||
OtherType& _source;
|
||||
};
|
||||
|
||||
template<typename Interface, typename Transform >
|
||||
class api;
|
||||
|
||||
class api_connection;
|
||||
|
||||
typedef uint32_t api_id_type;
|
||||
|
||||
class api_base
|
||||
{
|
||||
public:
|
||||
api_base() {}
|
||||
virtual ~api_base() {}
|
||||
|
||||
virtual uint64_t get_handle()const = 0;
|
||||
|
||||
virtual api_id_type register_api( api_connection& conn )const = 0;
|
||||
|
||||
// defined in api_connection.hpp
|
||||
template< typename T >
|
||||
api<T, identity_member> as();
|
||||
};
|
||||
typedef std::shared_ptr< api_base > api_ptr;
|
||||
|
||||
class api_connection;
|
||||
|
||||
template<typename Interface, typename Transform = identity_member >
|
||||
class api : public api_base {
|
||||
public:
|
||||
typedef vtable<Interface,Transform> vtable_type;
|
||||
|
||||
api():_vtable( std::make_shared<vtable_type>() ) {}
|
||||
|
||||
/** T is anything with pointer semantics */
|
||||
template<typename T >
|
||||
api( const T& p )
|
||||
:_vtable( std::make_shared<vtable_type>() )
|
||||
{
|
||||
_data = std::make_shared<fc::any>(p);
|
||||
T& ptr = boost::any_cast<T&>(*_data);
|
||||
auto& pointed_at = *ptr;
|
||||
typedef typename std::remove_reference<decltype(pointed_at)>::type source_vtable_type;
|
||||
_vtable->FC_CALL_MEMBER_TEMPLATE_KEYWORD visit_other( vtable_copy_visitor<source_vtable_type>(pointed_at) );
|
||||
}
|
||||
|
||||
api( const api& cpy ):_vtable(cpy._vtable),_data(cpy._data) {}
|
||||
virtual ~api() {}
|
||||
|
||||
friend bool operator == ( const api& a, const api& b ) { return a._data == b._data && a._vtable == b._vtable; }
|
||||
friend bool operator != ( const api& a, const api& b ) { return !(a._data == b._data && a._vtable == b._vtable); }
|
||||
virtual uint64_t get_handle()const override { return uint64_t(_data.get()); }
|
||||
virtual api_id_type register_api( api_connection& conn )const override; // defined in api_connection.hpp
|
||||
|
||||
vtable_type& operator*()const { FC_ASSERT( _vtable ); return *_vtable; }
|
||||
vtable_type* operator->()const { FC_ASSERT( _vtable ); return _vtable.get(); }
|
||||
|
||||
protected:
|
||||
std::shared_ptr<vtable_type> _vtable;
|
||||
std::shared_ptr<fc::any> _data;
|
||||
};
|
||||
|
||||
} // namespace fc
|
||||
|
||||
#include <boost/preprocessor/repeat.hpp>
|
||||
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
|
||||
#include <boost/preprocessor/repetition/enum_params.hpp>
|
||||
#include <boost/preprocessor/repetition/enum_trailing_params.hpp>
|
||||
#include <boost/preprocessor/facilities/empty.hpp>
|
||||
#include <boost/preprocessor/seq/for_each.hpp>
|
||||
#include <boost/preprocessor/stringize.hpp>
|
||||
|
||||
#define FC_API_VTABLE_DEFINE_MEMBER( r, data, elem ) \
|
||||
decltype(Transform::functor( (data*)nullptr, &data::elem)) elem;
|
||||
#define FC_API_VTABLE_DEFINE_VISIT_OTHER( r, data, elem ) \
|
||||
{ typedef typename Visitor::other_type OtherType; \
|
||||
v( BOOST_PP_STRINGIZE(elem), elem, &OtherType::elem ); }
|
||||
#define FC_API_VTABLE_DEFINE_VISIT( r, data, elem ) \
|
||||
v( BOOST_PP_STRINGIZE(elem), elem );
|
||||
|
||||
#define FC_API( CLASS, METHODS ) \
|
||||
namespace fc { \
|
||||
template<typename Transform> \
|
||||
struct vtable<CLASS,Transform> : public std::enable_shared_from_this<vtable<CLASS,Transform>> { \
|
||||
BOOST_PP_SEQ_FOR_EACH( FC_API_VTABLE_DEFINE_MEMBER, CLASS, METHODS ) \
|
||||
template<typename Visitor> \
|
||||
void visit_other( Visitor&& v ){ \
|
||||
BOOST_PP_SEQ_FOR_EACH( FC_API_VTABLE_DEFINE_VISIT_OTHER, CLASS, METHODS ) \
|
||||
} \
|
||||
template<typename Visitor> \
|
||||
void visit( Visitor&& v ){ \
|
||||
BOOST_PP_SEQ_FOR_EACH( FC_API_VTABLE_DEFINE_VISIT, CLASS, METHODS ) \
|
||||
} \
|
||||
}; \
|
||||
}
|
||||
|
||||
@@ -1,145 +0,0 @@
|
||||
#pragma once
|
||||
#include <fc/crypto/base64.hpp>
|
||||
#include <fc/variant.hpp>
|
||||
#include <fc/reflect/reflect.hpp>
|
||||
#include <fc/exception/exception.hpp>
|
||||
|
||||
namespace fc {
|
||||
|
||||
/**
|
||||
* Provides a fixed size array that is easier for templates to specialize
|
||||
* against or overload than T[N].
|
||||
*/
|
||||
template<typename T, size_t N>
|
||||
class array {
|
||||
public:
|
||||
/**
|
||||
* Checked indexing (when in debug build) that also simplifies dereferencing
|
||||
* when you have an array<T,N>*.
|
||||
*/
|
||||
///@{
|
||||
T& at( size_t pos ) { FC_ASSERT( pos < N, "array out-of-bounds" ); return data[pos]; }
|
||||
const T& at( size_t pos )const { FC_ASSERT( pos < N, "array out-of-bounds" ); return data[pos]; }
|
||||
///@}
|
||||
|
||||
T& operator[]( size_t pos ) { FC_ASSERT( pos < N, "array out-of-bounds" ); return data[pos]; }
|
||||
const T& operator[]( size_t pos )const { FC_ASSERT( pos < N, "array out-of-bounds" ); return data[pos]; }
|
||||
|
||||
|
||||
const T* begin()const { return &data[0]; }
|
||||
const T* end()const { return &data[N]; }
|
||||
|
||||
T* begin() { return &data[0]; }
|
||||
T* end() { return &data[N]; }
|
||||
|
||||
size_t size()const { return N; }
|
||||
|
||||
T data[N];
|
||||
};
|
||||
|
||||
/** provided for default 0 init */
|
||||
template<size_t N>
|
||||
class array<unsigned char,N>
|
||||
{
|
||||
public:
|
||||
typedef unsigned char T;
|
||||
array(){ memset( data, 0, sizeof(data) ); }
|
||||
/**
|
||||
* Checked indexing (when in debug build) that also simplifies dereferencing
|
||||
* when you have an array<T,N>*.
|
||||
*/
|
||||
///@{
|
||||
T& at( size_t pos ) { FC_ASSERT( pos < N, "array out-of-bounds" ); return data[pos]; }
|
||||
const T& at( size_t pos )const { FC_ASSERT( pos < N, "array out-of-bounds" ); return data[pos]; }
|
||||
///@}
|
||||
|
||||
T* begin() { return &data[0]; }
|
||||
const T* begin()const { return &data[0]; }
|
||||
const T* end()const { return &data[N]; }
|
||||
|
||||
size_t size()const { return N; }
|
||||
|
||||
T data[N];
|
||||
};
|
||||
|
||||
/** provided for default 0 init */
|
||||
template<size_t N>
|
||||
class array<char,N>
|
||||
{
|
||||
public:
|
||||
typedef char T;
|
||||
array(){ memset( data, 0, sizeof(data) ); }
|
||||
/**
|
||||
* Checked indexing (when in debug build) that also simplifies dereferencing
|
||||
* when you have an array<T,N>*.
|
||||
*/
|
||||
///@{
|
||||
T& at( size_t pos ) { FC_ASSERT( pos < N, "array out-of-bounds" ); return data[pos]; }
|
||||
const T& at( size_t pos )const { FC_ASSERT( pos < N, "array out-of-bounds" ); return data[pos]; }
|
||||
///@}
|
||||
|
||||
T* begin() { return &data[0]; }
|
||||
const T* begin()const { return &data[0]; }
|
||||
const T* end()const { return &data[N]; }
|
||||
|
||||
size_t size()const { return N; }
|
||||
|
||||
T data[N];
|
||||
};
|
||||
|
||||
template<typename T, size_t N>
|
||||
bool operator == ( const array<T,N>& a, const array<T,N>& b )
|
||||
{ return 0 == memcmp( a.data, b.data, N*sizeof(T) ); }
|
||||
template<typename T, size_t N>
|
||||
bool operator < ( const array<T,N>& a, const array<T,N>& b )
|
||||
{ return memcmp( a.data, b.data, N*sizeof(T) ) < 0 ; }
|
||||
|
||||
template<typename T, size_t N>
|
||||
bool operator > ( const array<T,N>& a, const array<T,N>& b )
|
||||
{ return memcmp( a.data, b.data, N*sizeof(T) ) > 0 ; }
|
||||
|
||||
template<typename T, size_t N>
|
||||
bool operator != ( const array<T,N>& a, const array<T,N>& b )
|
||||
{ return 0 != memcmp( a.data, b.data, N*sizeof(T) ); }
|
||||
|
||||
template<typename T, size_t N>
|
||||
void to_variant( const array<T,N>& bi, variant& v )
|
||||
{
|
||||
v = std::vector<char>( (const char*)&bi, ((const char*)&bi) + sizeof(bi) );
|
||||
}
|
||||
template<typename T, size_t N>
|
||||
void from_variant( const variant& v, array<T,N>& bi )
|
||||
{
|
||||
std::vector<char> ve = v.as< std::vector<char> >();
|
||||
if( ve.size() )
|
||||
{
|
||||
memcpy(bi.begin(), ve.data(), fc::min<size_t>(ve.size(),sizeof(bi)) );
|
||||
}
|
||||
else
|
||||
memset( bi.begin(), char(0), sizeof(bi) );
|
||||
}
|
||||
|
||||
|
||||
template<typename T,size_t N> struct get_typename< fc::array<T,N> >
|
||||
{
|
||||
static const char* name()
|
||||
{
|
||||
static std::string _name = std::string("fc::array<")+std::string(fc::get_typename<T>::name())+","+ fc::to_string(N) + ">";
|
||||
return _name.c_str();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#include <unordered_map>
|
||||
#include <fc/crypto/city.hpp>
|
||||
namespace std
|
||||
{
|
||||
template<typename T, size_t N>
|
||||
struct hash<fc::array<T,N> >
|
||||
{
|
||||
size_t operator()( const fc::array<T,N>& e )const
|
||||
{
|
||||
return fc::city_hash_size_t( (char*)&e, sizeof(e) );
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
namespace fc {
|
||||
|
||||
inline uint64_t endian_reverse_u64( uint64_t x )
|
||||
{
|
||||
return (((x >> 0x38) & 0xFF) )
|
||||
| (((x >> 0x30) & 0xFF) << 0x08)
|
||||
| (((x >> 0x28) & 0xFF) << 0x10)
|
||||
| (((x >> 0x20) & 0xFF) << 0x18)
|
||||
| (((x >> 0x18) & 0xFF) << 0x20)
|
||||
| (((x >> 0x10) & 0xFF) << 0x28)
|
||||
| (((x >> 0x08) & 0xFF) << 0x30)
|
||||
| (((x ) & 0xFF) << 0x38)
|
||||
;
|
||||
}
|
||||
|
||||
inline uint32_t endian_reverse_u32( uint32_t x )
|
||||
{
|
||||
return (((x >> 0x18) & 0xFF) )
|
||||
| (((x >> 0x10) & 0xFF) << 0x08)
|
||||
| (((x >> 0x08) & 0xFF) << 0x10)
|
||||
| (((x ) & 0xFF) << 0x18)
|
||||
;
|
||||
}
|
||||
|
||||
} // namespace fc
|
||||
@@ -1,621 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* *
|
||||
* Open Bloom Filter *
|
||||
* *
|
||||
* Author: Arash Partow - 2000 *
|
||||
* URL: http://www.partow.net *
|
||||
* URL: http://www.partow.net/programming/hashfunctions/index.html *
|
||||
* *
|
||||
* Copyright notice: *
|
||||
* Free use of the Open Bloom Filter Library is permitted under the *
|
||||
* guidelines and in accordance with the most current version of the *
|
||||
* Common Public License. *
|
||||
* http://www.opensource.org/licenses/cpl1.0.php *
|
||||
* *
|
||||
*********************************************************************
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <fc/reflect/reflect.hpp>
|
||||
|
||||
namespace fc {
|
||||
|
||||
|
||||
static const std::size_t bits_per_char = 0x08; // 8 bits in 1 char(unsigned)
|
||||
static const unsigned char bit_mask[bits_per_char] = {
|
||||
0x01, //00000001
|
||||
0x02, //00000010
|
||||
0x04, //00000100
|
||||
0x08, //00001000
|
||||
0x10, //00010000
|
||||
0x20, //00100000
|
||||
0x40, //01000000
|
||||
0x80 //10000000
|
||||
};
|
||||
|
||||
class bloom_parameters
|
||||
{
|
||||
public:
|
||||
|
||||
bloom_parameters()
|
||||
: minimum_size(1),
|
||||
maximum_size(std::numeric_limits<unsigned long long int>::max()),
|
||||
minimum_number_of_hashes(1),
|
||||
maximum_number_of_hashes(std::numeric_limits<unsigned int>::max()),
|
||||
projected_element_count(10000),
|
||||
false_positive_probability(1.0 / projected_element_count),
|
||||
random_seed(0xA5A5A5A55A5A5A5AULL)
|
||||
{}
|
||||
|
||||
virtual ~bloom_parameters()
|
||||
{}
|
||||
|
||||
inline bool operator!()
|
||||
{
|
||||
return (minimum_size > maximum_size) ||
|
||||
(minimum_number_of_hashes > maximum_number_of_hashes) ||
|
||||
(minimum_number_of_hashes < 1) ||
|
||||
(0 == maximum_number_of_hashes) ||
|
||||
(0 == projected_element_count) ||
|
||||
(false_positive_probability < 0.0) ||
|
||||
(std::numeric_limits<double>::infinity() == std::abs(false_positive_probability)) ||
|
||||
(0 == random_seed) ||
|
||||
(0xFFFFFFFFFFFFFFFFULL == random_seed);
|
||||
}
|
||||
|
||||
//Allowed min/max size of the bloom filter in bits
|
||||
unsigned long long int minimum_size;
|
||||
unsigned long long int maximum_size;
|
||||
|
||||
//Allowed min/max number of hash functions
|
||||
unsigned int minimum_number_of_hashes;
|
||||
unsigned int maximum_number_of_hashes;
|
||||
|
||||
//The approximate number of elements to be inserted
|
||||
//into the bloom filter, should be within one order
|
||||
//of magnitude. The default is 10000.
|
||||
unsigned long long int projected_element_count;
|
||||
|
||||
//The approximate false positive probability expected
|
||||
//from the bloom filter. The default is the reciprocal
|
||||
//of the projected_element_count.
|
||||
double false_positive_probability;
|
||||
|
||||
unsigned long long int random_seed;
|
||||
|
||||
struct optimal_parameters_t
|
||||
{
|
||||
optimal_parameters_t()
|
||||
: number_of_hashes(0),
|
||||
table_size(0)
|
||||
{}
|
||||
|
||||
unsigned int number_of_hashes;
|
||||
unsigned long long int table_size;
|
||||
};
|
||||
|
||||
optimal_parameters_t optimal_parameters;
|
||||
|
||||
virtual bool compute_optimal_parameters()
|
||||
{
|
||||
/*
|
||||
Note:
|
||||
The following will attempt to find the number of hash functions
|
||||
and minimum amount of storage bits required to construct a bloom
|
||||
filter consistent with the user defined false positive probability
|
||||
and estimated element insertion count.
|
||||
*/
|
||||
|
||||
if (!(*this))
|
||||
return false;
|
||||
|
||||
double min_m = std::numeric_limits<double>::infinity();
|
||||
double min_k = 0.0;
|
||||
double curr_m = 0.0;
|
||||
double k = 1.0;
|
||||
|
||||
while (k < 1000.0)
|
||||
{
|
||||
double numerator = (- k * projected_element_count);
|
||||
double denominator = std::log(1.0 - std::pow(false_positive_probability, 1.0 / k));
|
||||
curr_m = numerator / denominator;
|
||||
if (curr_m < min_m)
|
||||
{
|
||||
min_m = curr_m;
|
||||
min_k = k;
|
||||
}
|
||||
k += 1.0;
|
||||
}
|
||||
|
||||
optimal_parameters_t& optp = optimal_parameters;
|
||||
|
||||
optp.number_of_hashes = static_cast<unsigned int>(min_k);
|
||||
optp.table_size = static_cast<unsigned long long int>(min_m);
|
||||
optp.table_size += (((optp.table_size % bits_per_char) != 0) ? (bits_per_char - (optp.table_size % bits_per_char)) : 0);
|
||||
|
||||
if (optp.number_of_hashes < minimum_number_of_hashes)
|
||||
optp.number_of_hashes = minimum_number_of_hashes;
|
||||
else if (optp.number_of_hashes > maximum_number_of_hashes)
|
||||
optp.number_of_hashes = maximum_number_of_hashes;
|
||||
|
||||
if (optp.table_size < minimum_size)
|
||||
optp.table_size = minimum_size;
|
||||
else if (optp.table_size > maximum_size)
|
||||
optp.table_size = maximum_size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class bloom_filter
|
||||
{
|
||||
protected:
|
||||
|
||||
typedef unsigned int bloom_type;
|
||||
typedef unsigned char cell_type;
|
||||
|
||||
public:
|
||||
|
||||
bloom_filter()
|
||||
: salt_count_(0),
|
||||
table_size_(0),
|
||||
raw_table_size_(0),
|
||||
projected_element_count_(0),
|
||||
inserted_element_count_(0),
|
||||
random_seed_(0),
|
||||
desired_false_positive_probability_(0.0)
|
||||
{}
|
||||
|
||||
bloom_filter(const bloom_parameters& p)
|
||||
: projected_element_count_(p.projected_element_count),
|
||||
inserted_element_count_(0),
|
||||
random_seed_((p.random_seed * 0xA5A5A5A5) + 1),
|
||||
desired_false_positive_probability_(p.false_positive_probability)
|
||||
{
|
||||
salt_count_ = p.optimal_parameters.number_of_hashes;
|
||||
table_size_ = p.optimal_parameters.table_size;
|
||||
generate_unique_salt();
|
||||
raw_table_size_ = table_size_ / bits_per_char;
|
||||
|
||||
bit_table_.resize( static_cast<std::size_t>(raw_table_size_) );
|
||||
//bit_table_ = new cell_type[static_cast<std::size_t>(raw_table_size_)];
|
||||
std::fill_n(bit_table_.data(),raw_table_size_,0x00);
|
||||
}
|
||||
|
||||
bloom_filter(const bloom_filter& filter)
|
||||
{
|
||||
this->operator=(filter);
|
||||
}
|
||||
|
||||
inline bool operator == (const bloom_filter& f) const
|
||||
{
|
||||
if (this != &f)
|
||||
{
|
||||
return
|
||||
(salt_count_ == f.salt_count_) &&
|
||||
(table_size_ == f.table_size_) &&
|
||||
(raw_table_size_ == f.raw_table_size_) &&
|
||||
(projected_element_count_ == f.projected_element_count_) &&
|
||||
(inserted_element_count_ == f.inserted_element_count_) &&
|
||||
(random_seed_ == f.random_seed_) &&
|
||||
(desired_false_positive_probability_ == f.desired_false_positive_probability_) &&
|
||||
(salt_ == f.salt_) &&
|
||||
std::equal(f.bit_table_.data(),f.bit_table_.data() + raw_table_size_,bit_table_.data());
|
||||
}
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool operator != (const bloom_filter& f) const
|
||||
{
|
||||
return !operator==(f);
|
||||
}
|
||||
|
||||
inline bloom_filter& operator = (const bloom_filter& f)
|
||||
{
|
||||
if (this != &f)
|
||||
{
|
||||
salt_count_ = f.salt_count_;
|
||||
table_size_ = f.table_size_;
|
||||
raw_table_size_ = f.raw_table_size_;
|
||||
projected_element_count_ = f.projected_element_count_;
|
||||
inserted_element_count_ = f.inserted_element_count_;
|
||||
random_seed_ = f.random_seed_;
|
||||
desired_false_positive_probability_ = f.desired_false_positive_probability_;
|
||||
bit_table_.resize( raw_table_size_ );
|
||||
std::copy(f.bit_table_.data(),f.bit_table_.data() + raw_table_size_,bit_table_.data());
|
||||
salt_ = f.salt_;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
virtual ~bloom_filter()
|
||||
{
|
||||
}
|
||||
|
||||
inline bool operator!() const
|
||||
{
|
||||
return (0 == table_size_);
|
||||
}
|
||||
|
||||
inline void clear()
|
||||
{
|
||||
std::fill_n(bit_table_.data(),raw_table_size_,0x00);
|
||||
inserted_element_count_ = 0;
|
||||
}
|
||||
|
||||
inline void insert(const unsigned char* key_begin, const std::size_t& length)
|
||||
{
|
||||
std::size_t bit_index = 0;
|
||||
std::size_t bit = 0;
|
||||
for (std::size_t i = 0; i < salt_.size(); ++i)
|
||||
{
|
||||
compute_indices(hash_ap(key_begin,length,salt_[i]),bit_index,bit);
|
||||
bit_table_[bit_index / bits_per_char] |= bit_mask[bit];
|
||||
}
|
||||
++inserted_element_count_;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void insert(const T& t)
|
||||
{
|
||||
// Note: T must be a C++ POD type.
|
||||
insert(reinterpret_cast<const unsigned char*>(&t),sizeof(T));
|
||||
}
|
||||
|
||||
inline void insert(const std::string& key)
|
||||
{
|
||||
insert(reinterpret_cast<const unsigned char*>(key.c_str()),key.size());
|
||||
}
|
||||
|
||||
inline void insert(const char* data, const std::size_t& length)
|
||||
{
|
||||
insert(reinterpret_cast<const unsigned char*>(data),length);
|
||||
}
|
||||
|
||||
template<typename InputIterator>
|
||||
inline void insert(const InputIterator begin, const InputIterator end)
|
||||
{
|
||||
InputIterator itr = begin;
|
||||
while (end != itr)
|
||||
{
|
||||
insert(*(itr++));
|
||||
}
|
||||
}
|
||||
|
||||
inline virtual bool contains(const unsigned char* key_begin, const std::size_t length) const
|
||||
{
|
||||
std::size_t bit_index = 0;
|
||||
std::size_t bit = 0;
|
||||
for (std::size_t i = 0; i < salt_.size(); ++i)
|
||||
{
|
||||
compute_indices(hash_ap(key_begin,length,salt_[i]),bit_index,bit);
|
||||
if ((bit_table_[bit_index / bits_per_char] & bit_mask[bit]) != bit_mask[bit])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool contains(const T& t) const
|
||||
{
|
||||
return contains(reinterpret_cast<const unsigned char*>(&t),static_cast<std::size_t>(sizeof(T)));
|
||||
}
|
||||
|
||||
inline bool contains(const std::string& key) const
|
||||
{
|
||||
return contains(reinterpret_cast<const unsigned char*>(key.c_str()),key.size());
|
||||
}
|
||||
|
||||
inline bool contains(const char* data, const std::size_t& length) const
|
||||
{
|
||||
return contains(reinterpret_cast<const unsigned char*>(data),length);
|
||||
}
|
||||
|
||||
template<typename InputIterator>
|
||||
inline InputIterator contains_all(const InputIterator begin, const InputIterator end) const
|
||||
{
|
||||
InputIterator itr = begin;
|
||||
while (end != itr)
|
||||
{
|
||||
if (!contains(*itr))
|
||||
{
|
||||
return itr;
|
||||
}
|
||||
++itr;
|
||||
}
|
||||
return end;
|
||||
}
|
||||
|
||||
template<typename InputIterator>
|
||||
inline InputIterator contains_none(const InputIterator begin, const InputIterator end) const
|
||||
{
|
||||
InputIterator itr = begin;
|
||||
while (end != itr)
|
||||
{
|
||||
if (contains(*itr))
|
||||
{
|
||||
return itr;
|
||||
}
|
||||
++itr;
|
||||
}
|
||||
return end;
|
||||
}
|
||||
|
||||
inline virtual unsigned long long int size() const
|
||||
{
|
||||
return table_size_;
|
||||
}
|
||||
|
||||
inline std::size_t element_count() const
|
||||
{
|
||||
return inserted_element_count_;
|
||||
}
|
||||
|
||||
inline double effective_fpp() const
|
||||
{
|
||||
/*
|
||||
Note:
|
||||
The effective false positive probability is calculated using the
|
||||
designated table size and hash function count in conjunction with
|
||||
the current number of inserted elements - not the user defined
|
||||
predicated/expected number of inserted elements.
|
||||
*/
|
||||
return std::pow(1.0 - std::exp(-1.0 * salt_.size() * inserted_element_count_ / size()), 1.0 * salt_.size());
|
||||
}
|
||||
|
||||
inline bloom_filter& operator &= (const bloom_filter& f)
|
||||
{
|
||||
/* intersection */
|
||||
if (
|
||||
(salt_count_ == f.salt_count_) &&
|
||||
(table_size_ == f.table_size_) &&
|
||||
(random_seed_ == f.random_seed_)
|
||||
)
|
||||
{
|
||||
for (std::size_t i = 0; i < raw_table_size_; ++i)
|
||||
{
|
||||
bit_table_[i] &= f.bit_table_[i];
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline bloom_filter& operator |= (const bloom_filter& f)
|
||||
{
|
||||
/* union */
|
||||
if (
|
||||
(salt_count_ == f.salt_count_) &&
|
||||
(table_size_ == f.table_size_) &&
|
||||
(random_seed_ == f.random_seed_)
|
||||
)
|
||||
{
|
||||
for (std::size_t i = 0; i < raw_table_size_; ++i)
|
||||
{
|
||||
bit_table_[i] |= f.bit_table_[i];
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline bloom_filter& operator ^= (const bloom_filter& f)
|
||||
{
|
||||
/* difference */
|
||||
if (
|
||||
(salt_count_ == f.salt_count_) &&
|
||||
(table_size_ == f.table_size_) &&
|
||||
(random_seed_ == f.random_seed_)
|
||||
)
|
||||
{
|
||||
for (std::size_t i = 0; i < raw_table_size_; ++i)
|
||||
{
|
||||
bit_table_[i] ^= f.bit_table_[i];
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline const cell_type* table() const
|
||||
{
|
||||
return bit_table_.data();
|
||||
}
|
||||
|
||||
inline std::size_t hash_count()
|
||||
{
|
||||
return salt_.size();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
inline virtual void compute_indices(const bloom_type& hash, std::size_t& bit_index, std::size_t& bit) const
|
||||
{
|
||||
bit_index = hash % table_size_;
|
||||
bit = bit_index % bits_per_char;
|
||||
}
|
||||
|
||||
void generate_unique_salt()
|
||||
{
|
||||
/*
|
||||
Note:
|
||||
A distinct hash function need not be implementation-wise
|
||||
distinct. In the current implementation "seeding" a common
|
||||
hash function with different values seems to be adequate.
|
||||
*/
|
||||
const unsigned int predef_salt_count = 128;
|
||||
static const bloom_type predef_salt[predef_salt_count] =
|
||||
{
|
||||
0xAAAAAAAA, 0x55555555, 0x33333333, 0xCCCCCCCC,
|
||||
0x66666666, 0x99999999, 0xB5B5B5B5, 0x4B4B4B4B,
|
||||
0xAA55AA55, 0x55335533, 0x33CC33CC, 0xCC66CC66,
|
||||
0x66996699, 0x99B599B5, 0xB54BB54B, 0x4BAA4BAA,
|
||||
0xAA33AA33, 0x55CC55CC, 0x33663366, 0xCC99CC99,
|
||||
0x66B566B5, 0x994B994B, 0xB5AAB5AA, 0xAAAAAA33,
|
||||
0x555555CC, 0x33333366, 0xCCCCCC99, 0x666666B5,
|
||||
0x9999994B, 0xB5B5B5AA, 0xFFFFFFFF, 0xFFFF0000,
|
||||
0xB823D5EB, 0xC1191CDF, 0xF623AEB3, 0xDB58499F,
|
||||
0xC8D42E70, 0xB173F616, 0xA91A5967, 0xDA427D63,
|
||||
0xB1E8A2EA, 0xF6C0D155, 0x4909FEA3, 0xA68CC6A7,
|
||||
0xC395E782, 0xA26057EB, 0x0CD5DA28, 0x467C5492,
|
||||
0xF15E6982, 0x61C6FAD3, 0x9615E352, 0x6E9E355A,
|
||||
0x689B563E, 0x0C9831A8, 0x6753C18B, 0xA622689B,
|
||||
0x8CA63C47, 0x42CC2884, 0x8E89919B, 0x6EDBD7D3,
|
||||
0x15B6796C, 0x1D6FDFE4, 0x63FF9092, 0xE7401432,
|
||||
0xEFFE9412, 0xAEAEDF79, 0x9F245A31, 0x83C136FC,
|
||||
0xC3DA4A8C, 0xA5112C8C, 0x5271F491, 0x9A948DAB,
|
||||
0xCEE59A8D, 0xB5F525AB, 0x59D13217, 0x24E7C331,
|
||||
0x697C2103, 0x84B0A460, 0x86156DA9, 0xAEF2AC68,
|
||||
0x23243DA5, 0x3F649643, 0x5FA495A8, 0x67710DF8,
|
||||
0x9A6C499E, 0xDCFB0227, 0x46A43433, 0x1832B07A,
|
||||
0xC46AFF3C, 0xB9C8FFF0, 0xC9500467, 0x34431BDF,
|
||||
0xB652432B, 0xE367F12B, 0x427F4C1B, 0x224C006E,
|
||||
0x2E7E5A89, 0x96F99AA5, 0x0BEB452A, 0x2FD87C39,
|
||||
0x74B2E1FB, 0x222EFD24, 0xF357F60C, 0x440FCB1E,
|
||||
0x8BBE030F, 0x6704DC29, 0x1144D12F, 0x948B1355,
|
||||
0x6D8FD7E9, 0x1C11A014, 0xADD1592F, 0xFB3C712E,
|
||||
0xFC77642F, 0xF9C4CE8C, 0x31312FB9, 0x08B0DD79,
|
||||
0x318FA6E7, 0xC040D23D, 0xC0589AA7, 0x0CA5C075,
|
||||
0xF874B172, 0x0CF914D5, 0x784D3280, 0x4E8CFEBC,
|
||||
0xC569F575, 0xCDB2A091, 0x2CC016B4, 0x5C5F4421
|
||||
};
|
||||
|
||||
if (salt_count_ <= predef_salt_count)
|
||||
{
|
||||
std::copy(predef_salt,
|
||||
predef_salt + salt_count_,
|
||||
std::back_inserter(salt_));
|
||||
for (unsigned int i = 0; i < salt_.size(); ++i)
|
||||
{
|
||||
/*
|
||||
Note:
|
||||
This is done to integrate the user defined random seed,
|
||||
so as to allow for the generation of unique bloom filter
|
||||
instances.
|
||||
*/
|
||||
salt_[i] = salt_[i] * salt_[(i + 3) % salt_.size()] + static_cast<bloom_type>(random_seed_);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::copy(predef_salt,predef_salt + predef_salt_count,std::back_inserter(salt_));
|
||||
srand(static_cast<unsigned int>(random_seed_));
|
||||
while (salt_.size() < salt_count_)
|
||||
{
|
||||
bloom_type current_salt = static_cast<bloom_type>(rand()) * static_cast<bloom_type>(rand());
|
||||
if (0 == current_salt) continue;
|
||||
if (salt_.end() == std::find(salt_.begin(), salt_.end(), current_salt))
|
||||
{
|
||||
salt_.push_back(current_salt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline bloom_type hash_ap(const unsigned char* begin, std::size_t remaining_length, bloom_type hash) const
|
||||
{
|
||||
const unsigned char* itr = begin;
|
||||
unsigned int loop = 0;
|
||||
while (remaining_length >= 8)
|
||||
{
|
||||
const unsigned int& i1 = *(reinterpret_cast<const unsigned int*>(itr)); itr += sizeof(unsigned int);
|
||||
const unsigned int& i2 = *(reinterpret_cast<const unsigned int*>(itr)); itr += sizeof(unsigned int);
|
||||
hash ^= (hash << 7) ^ i1 * (hash >> 3) ^
|
||||
(~((hash << 11) + (i2 ^ (hash >> 5))));
|
||||
remaining_length -= 8;
|
||||
}
|
||||
if (remaining_length)
|
||||
{
|
||||
if (remaining_length >= 4)
|
||||
{
|
||||
const unsigned int& i = *(reinterpret_cast<const unsigned int*>(itr));
|
||||
if (loop & 0x01)
|
||||
hash ^= (hash << 7) ^ i * (hash >> 3);
|
||||
else
|
||||
hash ^= (~((hash << 11) + (i ^ (hash >> 5))));
|
||||
++loop;
|
||||
remaining_length -= 4;
|
||||
itr += sizeof(unsigned int);
|
||||
}
|
||||
if (remaining_length >= 2)
|
||||
{
|
||||
const unsigned short& i = *(reinterpret_cast<const unsigned short*>(itr));
|
||||
if (loop & 0x01)
|
||||
hash ^= (hash << 7) ^ i * (hash >> 3);
|
||||
else
|
||||
hash ^= (~((hash << 11) + (i ^ (hash >> 5))));
|
||||
++loop;
|
||||
remaining_length -= 2;
|
||||
itr += sizeof(unsigned short);
|
||||
}
|
||||
if (remaining_length)
|
||||
{
|
||||
hash += ((*itr) ^ (hash * 0xA5A5A5A5)) + loop;
|
||||
}
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
public:
|
||||
std::vector<bloom_type> salt_;
|
||||
std::vector<unsigned char> bit_table_;
|
||||
unsigned int salt_count_;
|
||||
unsigned long long int table_size_;
|
||||
unsigned long long int raw_table_size_;
|
||||
unsigned long long int projected_element_count_;
|
||||
unsigned int inserted_element_count_;
|
||||
unsigned long long int random_seed_;
|
||||
double desired_false_positive_probability_;
|
||||
};
|
||||
|
||||
inline bloom_filter operator & (const bloom_filter& a, const bloom_filter& b)
|
||||
{
|
||||
bloom_filter result = a;
|
||||
result &= b;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline bloom_filter operator | (const bloom_filter& a, const bloom_filter& b)
|
||||
{
|
||||
bloom_filter result = a;
|
||||
result |= b;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline bloom_filter operator ^ (const bloom_filter& a, const bloom_filter& b)
|
||||
{
|
||||
bloom_filter result = a;
|
||||
result ^= b;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
} // namespace fc
|
||||
|
||||
|
||||
FC_REFLECT( fc::bloom_filter, (salt_)(bit_table_)(salt_count_)(table_size_)(raw_table_size_)(projected_element_count_)(inserted_element_count_)(random_seed_)(desired_false_positive_probability_) )
|
||||
FC_REFLECT( fc::bloom_parameters::optimal_parameters_t, (number_of_hashes)(table_size) )
|
||||
FC_REFLECT( fc::bloom_parameters, (minimum_size)(maximum_size)(minimum_number_of_hashes)(maximum_number_of_hashes)(projected_element_count)(false_positive_probability)(random_seed)(optimal_parameters) )
|
||||
|
||||
/*
|
||||
Note 1:
|
||||
If it can be guaranteed that bits_per_char will be of the form 2^n then
|
||||
the following optimization can be used:
|
||||
|
||||
hash_table[bit_index >> n] |= bit_mask[bit_index & (bits_per_char - 1)];
|
||||
|
||||
Note 2:
|
||||
For performance reasons where possible when allocating memory it should
|
||||
be aligned (aligned_alloc) according to the architecture being used.
|
||||
*/
|
||||
@@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
namespace fc {
|
||||
|
||||
std::string smaz_compress( const std::string& in );
|
||||
std::string smaz_decompress( const std::string& compressed );
|
||||
|
||||
} // namespace fc
|
||||
@@ -1,10 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <fc/string.hpp>
|
||||
|
||||
namespace fc
|
||||
{
|
||||
|
||||
string zlib_compress(const string& in);
|
||||
|
||||
} // namespace fc
|
||||
@@ -1,160 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <fc/variant.hpp>
|
||||
#include <fc/io/raw_fwd.hpp>
|
||||
|
||||
namespace fc {
|
||||
|
||||
namespace raw {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<template<typename...> class Set, typename Stream, typename T, typename... U>
|
||||
inline void pack_set( Stream& s, const Set<T, U...>& value ) {
|
||||
FC_ASSERT( value.size() <= MAX_NUM_ARRAY_ELEMENTS );
|
||||
pack( s, unsigned_int((uint32_t)value.size()) );
|
||||
for( const auto& item : value ) {
|
||||
pack( s, item );
|
||||
}
|
||||
}
|
||||
|
||||
template<template<typename...> class Set, typename Stream, typename T, typename... U>
|
||||
inline void unpack_set( Stream& s, Set<T, U...>& value ) {
|
||||
unsigned_int size; unpack( s, size );
|
||||
FC_ASSERT( size.value <= MAX_NUM_ARRAY_ELEMENTS );
|
||||
value.clear();
|
||||
for( uint32_t i = 0; i < size.value; ++i ) {
|
||||
auto tmp = ::fc::detail::construct_maybe_with_allocator<T>( value.get_allocator() );
|
||||
unpack( s, tmp );
|
||||
value.insert( value.end(), std::move(tmp) );
|
||||
}
|
||||
}
|
||||
|
||||
template<template<typename...> class Set, typename Stream, typename T, typename... U>
|
||||
inline void unpack_flat_set( Stream& s, Set<T, U...>& value ) {
|
||||
unsigned_int size; unpack( s, size );
|
||||
FC_ASSERT( size.value <= MAX_NUM_ARRAY_ELEMENTS );
|
||||
value.clear();
|
||||
value.reserve( size.value );
|
||||
for( uint32_t i = 0; i < size.value; ++i ) {
|
||||
auto tmp = ::fc::detail::construct_maybe_with_allocator<T>( value.get_allocator() );
|
||||
unpack( s, tmp );
|
||||
value.insert( value.end(), std::move(tmp) );
|
||||
}
|
||||
}
|
||||
|
||||
template<template<typename...> class Map, typename Stream, typename K, typename V, typename... U>
|
||||
inline void pack_map( Stream& s, const Map<K, V, U...>& value ) {
|
||||
FC_ASSERT( value.size() <= MAX_NUM_ARRAY_ELEMENTS );
|
||||
pack( s, unsigned_int((uint32_t)value.size()) );
|
||||
for( const auto& item : value ) {
|
||||
pack( s, item );
|
||||
}
|
||||
}
|
||||
|
||||
template<template<typename...> class Map, typename Stream, typename K, typename V, typename... U>
|
||||
inline void unpack_map( Stream& s, Map<K, V, U...>& value ) {
|
||||
unsigned_int size; unpack( s, size );
|
||||
FC_ASSERT( size.value <= MAX_NUM_ARRAY_ELEMENTS );
|
||||
value.clear();
|
||||
for( uint32_t i = 0; i < size.value; ++i ) {
|
||||
auto tmp = ::fc::detail::default_construct_pair_maybe_with_allocator<K, V>( value.get_allocator() );
|
||||
unpack( s, tmp );
|
||||
value.insert( value.end(), std::move(tmp) );
|
||||
}
|
||||
}
|
||||
|
||||
template<template<typename...> class Map, typename Stream, typename K, typename V, typename... U>
|
||||
inline void unpack_flat_map( Stream& s, Map<K, V, U...>& value ) {
|
||||
unsigned_int size; unpack( s, size );
|
||||
FC_ASSERT( size.value <= MAX_NUM_ARRAY_ELEMENTS );
|
||||
value.clear();
|
||||
value.reserve( size.value );
|
||||
for( uint32_t i = 0; i < size.value; ++i ) {
|
||||
auto tmp = ::fc::detail::default_construct_pair_maybe_with_allocator<K, V>( value.get_allocator() );
|
||||
unpack( s, tmp );
|
||||
value.insert( value.end(), std::move(tmp) );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<template<typename...> class Set, typename T, typename... U>
|
||||
void to_variant_from_set( const Set<T, U...>& s, fc::variant& vo ) {
|
||||
FC_ASSERT( s.size() <= MAX_NUM_ARRAY_ELEMENTS );
|
||||
variants vars;
|
||||
vars.reserve( s.size() );
|
||||
for( const auto& item : s ) {
|
||||
vars.emplace_back( item );
|
||||
}
|
||||
vo = std::move( vars );
|
||||
}
|
||||
|
||||
template<template<typename...> class Set, typename T, typename... U>
|
||||
void from_variant_to_set( const fc::variant& v, Set< T, U... >& s ) {
|
||||
const variants& vars = v.get_array();
|
||||
FC_ASSERT( vars.size() <= MAX_NUM_ARRAY_ELEMENTS );
|
||||
s.clear();
|
||||
for( const auto& var : vars ) {
|
||||
auto item = construct_maybe_with_allocator<T>( s.get_allocator() );
|
||||
var.as<T>( item );
|
||||
s.insert( s.end(), std::move(item) );
|
||||
}
|
||||
}
|
||||
|
||||
template<template<typename...> class Set, typename T, typename... U>
|
||||
void from_variant_to_flat_set( const fc::variant& v, Set< T, U... >& s ) {
|
||||
const variants& vars = v.get_array();
|
||||
FC_ASSERT( vars.size() <= MAX_NUM_ARRAY_ELEMENTS );
|
||||
s.clear();
|
||||
s.reserve( vars.size() );
|
||||
for( const auto& var : vars ) {
|
||||
auto item = construct_maybe_with_allocator<T>( s.get_allocator() );
|
||||
var.as<T>( item );
|
||||
s.insert( s.end(), std::move(item) );
|
||||
}
|
||||
}
|
||||
|
||||
template<template<typename...> class Map, typename K, typename V, typename... U >
|
||||
void to_variant_from_map( const Map< K, V, U... >& m, fc::variant& vo ) {
|
||||
FC_ASSERT( m.size() <= MAX_NUM_ARRAY_ELEMENTS );
|
||||
variants vars;
|
||||
vars.reserve( m.size() );
|
||||
for( const auto& item : m ) {
|
||||
vars.emplace_back( item );
|
||||
}
|
||||
vo = std::move( vars );
|
||||
}
|
||||
|
||||
template<template<typename...> class Map, typename K, typename V, typename... U>
|
||||
void from_variant_to_map( const variant& v, Map<K, V, U...>& m ) {
|
||||
const variants& vars = v.get_array();
|
||||
FC_ASSERT( vars.size() <= MAX_NUM_ARRAY_ELEMENTS );
|
||||
m.clear();
|
||||
for( const auto& var : vars ) {
|
||||
auto item = default_construct_pair_maybe_with_allocator<K, V>( m.get_allocator() );
|
||||
var.as< std::pair<K,V> >( item );
|
||||
m.insert( m.end(), std::move(item) );
|
||||
}
|
||||
}
|
||||
|
||||
template<template<typename...> class Map, typename K, typename V, typename... U>
|
||||
void from_variant_to_flat_map( const variant& v, Map<K, V, U...>& m ) {
|
||||
const variants& vars = v.get_array();
|
||||
FC_ASSERT( vars.size() <= MAX_NUM_ARRAY_ELEMENTS );
|
||||
m.clear();
|
||||
m.reserve( vars.size() );
|
||||
for( const auto& var : vars ) {
|
||||
auto item = default_construct_pair_maybe_with_allocator<K, V>( m.get_allocator() );
|
||||
var.as< std::pair<K,V> >( item );
|
||||
m.insert( m.end(), std::move(item) );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <deque>
|
||||
#include <fc/io/raw.hpp>
|
||||
|
||||
namespace fc {
|
||||
namespace raw {
|
||||
|
||||
|
||||
} // namespace raw
|
||||
|
||||
} // namespace fc
|
||||
@@ -1,13 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <deque>
|
||||
|
||||
namespace fc {
|
||||
|
||||
namespace raw {
|
||||
template<typename Stream, typename T>
|
||||
void pack( Stream& s, const std::deque<T>& value );
|
||||
template<typename Stream, typename T>
|
||||
void unpack( Stream& s, std::deque<T>& value );
|
||||
}
|
||||
} // namespace fc
|
||||
@@ -1,186 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <fc/container/flat_fwd.hpp>
|
||||
#include <fc/container/container_detail.hpp>
|
||||
#include <boost/container/flat_map.hpp>
|
||||
#include <boost/container/flat_set.hpp>
|
||||
#include <fc/crypto/hex.hpp>
|
||||
|
||||
namespace fc {
|
||||
|
||||
namespace raw {
|
||||
|
||||
template<typename Stream, typename T, typename A>
|
||||
void pack( Stream& s, const boost::container::vector<T, A>& value ) {
|
||||
FC_ASSERT( value.size() <= MAX_NUM_ARRAY_ELEMENTS );
|
||||
pack( s, unsigned_int((uint32_t)value.size()) );
|
||||
if( !std::is_fundamental<T>::value ) {
|
||||
for( const auto& item : value ) {
|
||||
pack( s, item );
|
||||
}
|
||||
} else if( value.size() ) {
|
||||
s.write( (const char*)value.data(), value.size() );
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Stream, typename T, typename A>
|
||||
void unpack( Stream& s, boost::container::vector<T, A>& value ) {
|
||||
unsigned_int size;
|
||||
unpack( s, size );
|
||||
FC_ASSERT( size.value <= MAX_NUM_ARRAY_ELEMENTS );
|
||||
value.clear();
|
||||
value.resize( size.value );
|
||||
if( !std::is_fundamental<T>::value ) {
|
||||
for( auto& item : value ) {
|
||||
unpack( s, item );
|
||||
}
|
||||
} else if( value.size() ) {
|
||||
s.read( (char*)value.data(), value.size() );
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Stream, typename A>
|
||||
void pack( Stream& s, const boost::container::vector<char, A>& value ) {
|
||||
FC_ASSERT( value.size() <= MAX_SIZE_OF_BYTE_ARRAYS );
|
||||
pack( s, unsigned_int((uint32_t)value.size()) );
|
||||
if( value.size() )
|
||||
s.write( (const char*)value.data(), value.size() );
|
||||
}
|
||||
|
||||
template<typename Stream, typename A>
|
||||
void unpack( Stream& s, boost::container::vector<char, A>& value ) {
|
||||
unsigned_int size;
|
||||
unpack( s, size );
|
||||
FC_ASSERT( size.value <= MAX_SIZE_OF_BYTE_ARRAYS );
|
||||
value.clear();
|
||||
value.resize( size.value );
|
||||
if( value.size() )
|
||||
s.read( (char*)value.data(), value.size() );
|
||||
}
|
||||
|
||||
template<typename Stream, typename T, typename... U>
|
||||
void pack( Stream& s, const flat_set<T, U...>& value ) {
|
||||
detail::pack_set( s, value );
|
||||
}
|
||||
|
||||
template<typename Stream, typename T, typename... U>
|
||||
void unpack( Stream& s, flat_set<T, U...>& value ) {
|
||||
detail::unpack_flat_set( s, value );
|
||||
}
|
||||
|
||||
template<typename Stream, typename T, typename... U>
|
||||
void pack( Stream& s, const flat_multiset<T, U...>& value ) {
|
||||
detail::pack_set( s, value );
|
||||
}
|
||||
|
||||
template<typename Stream, typename T, typename... U>
|
||||
void unpack( Stream& s, flat_multiset<T, U...>& value ) {
|
||||
detail::unpack_flat_set( s, value );
|
||||
}
|
||||
|
||||
template<typename Stream, typename K, typename V, typename... U>
|
||||
void pack( Stream& s, const flat_map<K, V, U...>& value ) {
|
||||
detail::pack_map( s, value );
|
||||
}
|
||||
|
||||
template<typename Stream, typename K, typename V, typename... U>
|
||||
void unpack( Stream& s, flat_map<K, V, U...>& value ) {
|
||||
detail::unpack_flat_map( s, value );
|
||||
}
|
||||
|
||||
template<typename Stream, typename K, typename V, typename... U>
|
||||
void pack( Stream& s, const flat_multimap<K, V, U...>& value ) {
|
||||
detail::pack_map( s, value );
|
||||
}
|
||||
|
||||
template<typename Stream, typename K, typename V, typename... U>
|
||||
void unpack( Stream& s, flat_multimap<K, V, U...>& value ) {
|
||||
detail::unpack_flat_map( s, value );
|
||||
}
|
||||
|
||||
} // namespace raw
|
||||
|
||||
template<typename T, typename... U>
|
||||
void to_variant( const boost::container::vector<T, U...>& vec, fc::variant& vo ) {
|
||||
FC_ASSERT( vec.size() <= MAX_NUM_ARRAY_ELEMENTS );
|
||||
variants vars;
|
||||
vars.reserve( vec.size() );
|
||||
for( const auto& item : vec ) {
|
||||
vars.emplace_back( item );
|
||||
}
|
||||
vo = std::move(vars);
|
||||
}
|
||||
|
||||
template<typename T, typename... U>
|
||||
void from_variant( const fc::variant& v, boost::container::vector<T, U...>& vec ) {
|
||||
const variants& vars = v.get_array();
|
||||
FC_ASSERT( vars.size() <= MAX_NUM_ARRAY_ELEMENTS );
|
||||
vec.clear();
|
||||
vec.resize( vars.size() );
|
||||
for( uint32_t i = 0; i < vars.size(); ++i ) {
|
||||
from_variant( vars[i], vec[i] );
|
||||
}
|
||||
}
|
||||
|
||||
template<typename... U>
|
||||
void to_variant( const boost::container::vector<char, U...>& vec, fc::variant& vo ) {
|
||||
FC_ASSERT( vec.size() <= MAX_SIZE_OF_BYTE_ARRAYS );
|
||||
if( vec.size() )
|
||||
vo = variant( fc::to_hex( vec.data(), vec.size() ) );
|
||||
else
|
||||
vo = "";
|
||||
}
|
||||
|
||||
template<typename... U>
|
||||
void from_variant( const fc::variant& v, boost::container::vector<char, U...>& vec )
|
||||
{
|
||||
const auto& str = v.get_string();
|
||||
FC_ASSERT( str.size() <= 2*MAX_SIZE_OF_BYTE_ARRAYS ); // Doubled because hex strings needs two characters per byte
|
||||
vec.resize( str.size() / 2 );
|
||||
if( vec.size() ) {
|
||||
size_t r = fc::from_hex( str, vec.data(), vec.size() );
|
||||
FC_ASSERT( r == vec.size() );
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, typename... U>
|
||||
void to_variant( const flat_set< T, U... >& s, fc::variant& vo ) {
|
||||
detail::to_variant_from_set( s, vo );
|
||||
}
|
||||
|
||||
template<typename T, typename... U>
|
||||
void from_variant( const fc::variant& v, flat_set< T, U... >& s ) {
|
||||
detail::from_variant_to_flat_set( v, s );
|
||||
}
|
||||
|
||||
template<typename T, typename... U>
|
||||
void to_variant( const flat_multiset< T, U... >& s, fc::variant& vo ) {
|
||||
detail::to_variant_from_set( s, vo );
|
||||
}
|
||||
|
||||
template<typename T, typename... U>
|
||||
void from_variant( const fc::variant& v, flat_multiset< T, U... >& s ) {
|
||||
detail::from_variant_to_flat_set( v, s );
|
||||
}
|
||||
|
||||
template<typename K, typename V, typename... U >
|
||||
void to_variant( const flat_map< K, V, U... >& m, fc::variant& vo ) {
|
||||
detail::to_variant_from_map( m, vo );
|
||||
}
|
||||
|
||||
template<typename K, typename V, typename... U>
|
||||
void from_variant( const variant& v, flat_map<K, V, U...>& m ) {
|
||||
detail::from_variant_to_flat_map( v, m );
|
||||
}
|
||||
|
||||
template<typename K, typename V, typename... U >
|
||||
void to_variant( const flat_multimap< K, V, U... >& m, fc::variant& vo ) {
|
||||
detail::to_variant_from_map( m, vo );
|
||||
}
|
||||
|
||||
template<typename K, typename V, typename... U>
|
||||
void from_variant( const variant& v, flat_multimap<K, V, U...>& m ) {
|
||||
detail::from_variant_to_flat_map( v, m );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <boost/container/flat_map.hpp>
|
||||
#include <boost/container/flat_set.hpp>
|
||||
#include <boost/container/vector.hpp>
|
||||
|
||||
#include <boost/interprocess/containers/vector.hpp> // only added to maintain backwards compatibility with existing consumers of fc (can eventually remove)
|
||||
|
||||
namespace fc {
|
||||
|
||||
using boost::container::flat_set;
|
||||
using boost::container::flat_multiset;
|
||||
using boost::container::flat_map;
|
||||
using boost::container::flat_multimap;
|
||||
|
||||
namespace raw {
|
||||
|
||||
template<typename Stream, typename T, typename... U>
|
||||
void pack( Stream& s, const boost::container::vector<T, U...>& value );
|
||||
template<typename Stream, typename T, typename... U>
|
||||
void unpack( Stream& s, boost::container::vector<T, U...>& value );
|
||||
|
||||
template<typename Stream, typename T, typename... U>
|
||||
void pack( Stream& s, const flat_set<T, U...>& value );
|
||||
template<typename Stream, typename T, typename... U>
|
||||
void unpack( Stream& s, flat_set<T, U...>& value );
|
||||
|
||||
template<typename Stream, typename T, typename... U>
|
||||
void pack( Stream& s, const flat_multiset<T, U...>& value );
|
||||
template<typename Stream, typename T, typename... U>
|
||||
void unpack( Stream& s, flat_multiset<T, U...>& value );
|
||||
|
||||
template<typename Stream, typename K, typename V, typename... U>
|
||||
void pack( Stream& s, const flat_map<K, V, U...>& value );
|
||||
template<typename Stream, typename K, typename V, typename... U>
|
||||
void unpack( Stream& s, flat_map<K, V, U...>& value ) ;
|
||||
|
||||
template<typename Stream, typename K, typename V, typename... U>
|
||||
void pack( Stream& s, const flat_multimap<K, V, U...>& value );
|
||||
template<typename Stream, typename K, typename V, typename... U>
|
||||
void unpack( Stream& s, flat_multimap<K, V, U...>& value ) ;
|
||||
|
||||
} // namespace raw
|
||||
|
||||
} // fc
|
||||
@@ -1,124 +0,0 @@
|
||||
#pragma once
|
||||
#include <fc/exception/exception.hpp>
|
||||
#include <fc/io/cfile.hpp>
|
||||
#include <fc/io/datastream.hpp>
|
||||
#include <fc/io/fstream.hpp>
|
||||
#include <fc/io/raw.hpp>
|
||||
#include <fstream>
|
||||
|
||||
namespace fc {
|
||||
|
||||
/**
|
||||
* Specialize tracked::memory_size() if obj does not provide a memory_size() method that represents memory size.
|
||||
*/
|
||||
namespace tracked {
|
||||
template<typename T>
|
||||
size_t memory_size( const T& obj ) {
|
||||
return obj.memory_size();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @class tracked_storage
|
||||
* @brief tracks the size of storage allocated to its underlying multi_index
|
||||
*
|
||||
* This class wraps a multi_index container and tracks the memory allocated as
|
||||
* the container creates, modifies, and deletes. It also provides read and write
|
||||
* methods for persistence.
|
||||
*
|
||||
* Requires ContainerType::value_type to have a size() method that represents the
|
||||
* memory used for that object or specialized tracked::size() and is required to
|
||||
* be a pack/unpack-able type.
|
||||
*/
|
||||
|
||||
template <typename ContainerType>
|
||||
class tracked_storage {
|
||||
private:
|
||||
size_t _memory_size = 0;
|
||||
ContainerType _index;
|
||||
public:
|
||||
typedef typename ContainerType::template nth_index<0>::type primary_index_type;
|
||||
|
||||
tracked_storage() = default;
|
||||
|
||||
// read in the contents of a persisted tracked_storage and prevent reading in
|
||||
// more stored objects once max_memory is reached.
|
||||
// returns true if entire persisted tracked_storage was read
|
||||
bool read(fc::cfile_datastream& ds, size_t max_memory) {
|
||||
auto container_size = _index.size();
|
||||
fc::raw::unpack(ds, container_size);
|
||||
for (size_t i = 0; i < container_size; ++i) {
|
||||
if (memory_size() >= max_memory) {
|
||||
return false;
|
||||
}
|
||||
typename ContainerType::value_type v;
|
||||
fc::raw::unpack(ds, v);
|
||||
insert(std::move(v));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void write(fc::cfile& dat_content) const {
|
||||
const auto container_size = _index.size();
|
||||
dat_content.write( reinterpret_cast<const char*>(&container_size), sizeof(container_size) );
|
||||
|
||||
for (const auto& item : _index) {
|
||||
auto data = fc::raw::pack(item);
|
||||
dat_content.write(data.data(), data.size());
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<typename primary_index_type::iterator, bool> insert(typename ContainerType::value_type obj) {
|
||||
const auto size = tracked::memory_size(obj);
|
||||
auto result = _index.insert(std::move(obj));
|
||||
if (result.second) {
|
||||
_memory_size += size;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename Key>
|
||||
typename primary_index_type::iterator find(const Key& key) {
|
||||
primary_index_type& primary_idx = _index.template get<0>();
|
||||
return primary_idx.find(key);
|
||||
}
|
||||
|
||||
template<typename Key>
|
||||
typename primary_index_type::const_iterator find(const Key& key) const {
|
||||
const primary_index_type& primary_idx = _index.template get<0>();
|
||||
return primary_idx.find(key);
|
||||
}
|
||||
|
||||
template<typename Lam>
|
||||
void modify(typename primary_index_type::iterator itr, Lam lam) {
|
||||
_memory_size -= tracked::memory_size(*itr);
|
||||
if (_index.modify( itr, std::move(lam))) {
|
||||
_memory_size += tracked::memory_size(*itr);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Key>
|
||||
void erase(const Key& key) {
|
||||
auto itr = _index.find(key);
|
||||
if (itr == _index.end())
|
||||
return;
|
||||
|
||||
_memory_size -= tracked::memory_size(*itr);
|
||||
_index.erase(itr);
|
||||
}
|
||||
|
||||
void erase(typename primary_index_type::iterator itr) {
|
||||
_memory_size -= tracked::memory_size(*itr);
|
||||
_index.erase(itr);
|
||||
}
|
||||
|
||||
size_t memory_size() const {
|
||||
return _memory_size;
|
||||
}
|
||||
|
||||
const ContainerType& index() const {
|
||||
return _index;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
#pragma once
|
||||
#include <fc/crypto/sha512.hpp>
|
||||
#include <fc/crypto/sha256.hpp>
|
||||
#include <fc/uint128.hpp>
|
||||
#include <fc/fwd.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace fc {
|
||||
class path;
|
||||
|
||||
class aes_encoder
|
||||
{
|
||||
public:
|
||||
void init( const fc::sha256& key, const fc::uint128& init_value );
|
||||
uint32_t encode( const char* plaintxt, uint32_t len, char* ciphertxt );
|
||||
// uint32_t final_encode( char* ciphertxt );
|
||||
|
||||
private:
|
||||
struct impl;
|
||||
fc::fwd<impl,96> my;
|
||||
};
|
||||
class aes_decoder
|
||||
{
|
||||
public:
|
||||
void init( const fc::sha256& key, const fc::uint128& init_value );
|
||||
uint32_t decode( const char* ciphertxt, uint32_t len, char* plaintext );
|
||||
// uint32_t final_decode( char* plaintext );
|
||||
|
||||
private:
|
||||
struct impl;
|
||||
fc::fwd<impl,96> my;
|
||||
};
|
||||
|
||||
unsigned aes_encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key,
|
||||
unsigned char *iv, unsigned char *ciphertext);
|
||||
unsigned aes_decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key,
|
||||
unsigned char *iv, unsigned char *plaintext);
|
||||
unsigned aes_cfb_decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key,
|
||||
unsigned char *iv, unsigned char *plaintext);
|
||||
|
||||
std::vector<char> aes_encrypt( const fc::sha512& key, const std::vector<char>& plain_text );
|
||||
std::vector<char> aes_decrypt( const fc::sha512& key, const std::vector<char>& cipher_text );
|
||||
|
||||
/** encrypts plain_text and then includes a checksum that enables us to verify the integrety of
|
||||
* the file / key prior to decryption.
|
||||
*/
|
||||
void aes_save( const fc::path& file, const fc::sha512& key, std::vector<char> plain_text );
|
||||
|
||||
/**
|
||||
* recovers the plain_text saved via aes_save()
|
||||
*/
|
||||
std::vector<char> aes_load( const fc::path& file, const fc::sha512& key );
|
||||
|
||||
} // namespace fc
|
||||
@@ -1,25 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <cstdint>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
#include <fc/utility.hpp>
|
||||
|
||||
namespace fc {
|
||||
using bytes = std::vector<char>;
|
||||
|
||||
enum class alt_bn128_error : int32_t {
|
||||
operand_component_invalid,
|
||||
operand_not_in_curve,
|
||||
pairing_list_size_error,
|
||||
operand_outside_g2,
|
||||
input_len_error,
|
||||
invalid_scalar_size
|
||||
};
|
||||
|
||||
std::variant<alt_bn128_error, bytes> alt_bn128_add(const bytes& op1, const bytes& op2);
|
||||
std::variant<alt_bn128_error, bytes> alt_bn128_mul(const bytes& g1_point, const bytes& scalar);
|
||||
std::variant<alt_bn128_error, bool> alt_bn128_pair(const bytes& g1_g2_pairs, const yield_function_t& yield);
|
||||
|
||||
} // fc
|
||||
@@ -1,10 +0,0 @@
|
||||
#pragma once
|
||||
#include <fc/vector.hpp>
|
||||
#include <fc/string.hpp>
|
||||
|
||||
namespace fc
|
||||
{
|
||||
std::vector<char> from_base32( const fc::string& b32 );
|
||||
fc::string to_base32( const std::vector<char>& vec );
|
||||
fc::string to_base32( const char* data, size_t len );
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
#pragma once
|
||||
#include <fc/vector.hpp>
|
||||
#include <fc/string.hpp>
|
||||
|
||||
namespace fc
|
||||
{
|
||||
std::vector<char> from_base36( const fc::string& b36 );
|
||||
fc::string to_base36( const std::vector<char>& vec );
|
||||
fc::string to_base36( const char* data, size_t len );
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
#pragma once
|
||||
#include <fc/string.hpp>
|
||||
#include <fc/time.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace fc {
|
||||
std::string to_base58( const char* d, size_t s, const fc::yield_function_t& yield );
|
||||
std::string to_base58( const std::vector<char>& data, const fc::yield_function_t& yield );
|
||||
std::vector<char> from_base58( const std::string& base58_str );
|
||||
size_t from_base58( const std::string& base58_str, char* out_data, size_t out_data_len );
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
namespace fc {
|
||||
std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len);
|
||||
inline std::string base64_encode(char const* bytes_to_encode, unsigned int in_len) { return base64_encode( (unsigned char const*)bytes_to_encode, in_len); }
|
||||
std::string base64_encode( const std::string& enc );
|
||||
std::string base64_decode( const std::string& encoded_string);
|
||||
|
||||
std::string base64url_encode(unsigned char const* bytes_to_encode, unsigned int in_len);
|
||||
inline std::string base64url_encode(char const* bytes_to_encode, unsigned int in_len) { return base64url_encode( (unsigned char const*)bytes_to_encode, in_len); }
|
||||
std::string base64url_encode( const std::string& enc );
|
||||
std::string base64url_decode( const std::string& encoded_string);
|
||||
} // namespace fc
|
||||
@@ -1,76 +0,0 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <fc/string.hpp>
|
||||
#include <fc/vector.hpp>
|
||||
|
||||
struct bignum_st;
|
||||
typedef bignum_st BIGNUM;
|
||||
|
||||
namespace fc {
|
||||
class bigint {
|
||||
public:
|
||||
bigint( const std::vector<char>& bige );
|
||||
bigint( const char* bige, uint32_t l );
|
||||
bigint(uint64_t value);
|
||||
bigint( );
|
||||
bigint( const bigint& c );
|
||||
bigint( bigint&& c );
|
||||
explicit bigint( BIGNUM* n );
|
||||
~bigint();
|
||||
|
||||
bigint& operator = ( const bigint& a );
|
||||
bigint& operator = ( bigint&& a );
|
||||
|
||||
explicit operator bool()const;
|
||||
|
||||
bool is_negative()const;
|
||||
int64_t to_int64()const;
|
||||
|
||||
int64_t log2()const;
|
||||
bigint exp( const bigint& c )const;
|
||||
|
||||
static bigint random( uint32_t bits, int t, int );
|
||||
|
||||
bool operator < ( const bigint& c )const;
|
||||
bool operator > ( const bigint& c )const;
|
||||
bool operator >= ( const bigint& c )const;
|
||||
bool operator == ( const bigint& c )const;
|
||||
bool operator != ( const bigint& c )const;
|
||||
|
||||
bigint operator + ( const bigint& a )const;
|
||||
bigint operator * ( const bigint& a )const;
|
||||
bigint operator / ( const bigint& a )const;
|
||||
bigint operator % ( const bigint& a )const;
|
||||
bigint operator /= ( const bigint& a );
|
||||
bigint operator *= ( const bigint& a );
|
||||
bigint& operator += ( const bigint& a );
|
||||
bigint& operator -= ( const bigint& a );
|
||||
bigint& operator <<= ( uint32_t i );
|
||||
bigint& operator >>= ( uint32_t i );
|
||||
bigint operator - ( const bigint& a )const;
|
||||
|
||||
|
||||
bigint operator++(int);
|
||||
bigint& operator++();
|
||||
bigint operator--(int);
|
||||
bigint& operator--();
|
||||
|
||||
operator fc::string()const;
|
||||
|
||||
// returns bignum as bigendian bytes
|
||||
operator std::vector<char>()const;
|
||||
|
||||
BIGNUM* dup()const;
|
||||
|
||||
BIGNUM* get()const { return n; }
|
||||
private:
|
||||
BIGNUM* n;
|
||||
};
|
||||
|
||||
class variant;
|
||||
/** encodes the big int as base64 string, or a number */
|
||||
void to_variant( const bigint& bi, variant& v );
|
||||
/** decodes the big int as base64 string, or a number */
|
||||
void from_variant( const variant& v, bigint& bi );
|
||||
} // namespace fc
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user