Compare commits

...

4 Commits

24 changed files with 16447 additions and 1595 deletions

6
.cargo/config Normal file
View File

@ -0,0 +1,6 @@
[http]
timeout = 30 # timeout for each HTTP request, in seconds
multiplexing = false # HTTP/2 multiplexing
[net]
retry = 50 # network retries

View File

@ -1,38 +0,0 @@
version: 2.1
orbs:
docker: circleci/docker@1.5.0
jobs:
Build:
docker:
- image: circleci/rust:latest
resource_class: xlarge
environment:
RUST_BACKTRACE: 1
steps:
- checkout
- run: |
sudo bash .github/download_marine.sh
- restore_cache:
keys:
- trust-graph00-{{ checksum "./Cargo.lock" }}
- run: |
rustup target add wasm32-wasi
cargo test --no-fail-fast --release --all-features --
cd ./service
./build.sh
mkdir -p data
cargo test --no-fail-fast --release --all-features -- --test-threads=1
- save_cache:
paths:
- ~/.cargo
- ~/.rustup
key: trust-graph00-{{ checksum "./Cargo.lock" }}
workflows:
version: 2
CircleCI:
jobs:
- Build

View File

@ -3,7 +3,7 @@ set -o pipefail -o errexit -o nounset
set -x
MARINE_RELEASE="https://api.github.com/repos/fluencelabs/marine/releases/latest"
OUT_DIR=/usr/local/bin
OUT_DIR=~/.bin
# get metadata about release
curl -s -H "Accept: application/vnd.github.v3+json" $MARINE_RELEASE |

View File

@ -1,5 +1,6 @@
{
"template": "${{CHANGELOG}}\n\n${{UNCATEGORIZED}}",
"template": "## Changes since ${{FROM_TAG}}\n\n${{CHANGELOG}}\n\n${{UNCATEGORIZED}}",
"pr_template": "- #${{NUMBER}} ${{TITLE}}",
"empty_template": "- no changes"
"empty_template": "## No changes since ${{FROM_TAG}}",
"sort": "DESC"
}

View File

@ -6,9 +6,9 @@ on:
- "v*"
jobs:
npm-publish:
release:
name: "Publish"
runs-on: ubuntu-latest
runs-on: builder
container: rust
defaults:
run:
@ -22,44 +22,54 @@ jobs:
- name: Set env
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
- run: mkdir -p ~/.bin
- run: echo "~/.bin" >> $GITHUB_PATH
- name: Download jq
run: |
curl -L https://github.com/stedolan/jq/releases/download/jq-1.5/jq-linux64 -o /usr/local/bin/jq
chmod +x /usr/local/bin/jq
curl -L https://github.com/stedolan/jq/releases/download/jq-1.5/jq-linux64 -o ~/.bin/jq
chmod +x ~/.bin/jq
- name: Download marine
run: bash $GITHUB_WORKSPACE/.github/download_marine.sh
- uses: actions/setup-java@v2
with:
distribution: 'adopt'
java-version: '11'
- name: Cache npm
uses: actions/cache@v2
with:
path: ~/.npm
key: ${{ runner.os }}-node-v01-${{ hashFiles('**/package-lock.json') }}
key: ${{ runner.os }}-node-v03-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-v01-
${{ runner.os }}-node-v03-
- uses: actions/setup-node@v2
with:
node-version: "15"
registry-url: "https://registry.npmjs.org"
- uses: actions/cache@v2
- name: Cache cargo
uses: actions/cache@v2
with:
path: |
~/.cargo/registry
~/.cargo/git
~/.cargo/bin
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Install toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: nightly-2022-01-16
target: wasm32-wasi
override: true
- name: Install Rust
working-directory: ./service
run: |
rustup toolchain install nightly-2022-01-16-x86_64-unknown-linux-gnu
rustup default nightly-2022-01-16-x86_64-unknown-linux-gnu
rustup override set nightly-2022-01-16-x86_64-unknown-linux-gnu
rustup target add wasm32-wasi --toolchain nightly-2022-01-16-x86_64-unknown-linux-gnu
### Build
- name: trust-graph.wasm
- name: Build trust-graph
working-directory: ./service
run: ./build.sh
@ -69,7 +79,7 @@ jobs:
npm i
npm run build
- name: Create builtin distribution package
- name: Create distribution package
run: |
./builtin-package/package.sh
@ -81,15 +91,15 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
## Publish
- name: Release
### Publish
- name: Release to GitHub
id: release
uses: softprops/action-gh-release@v1
with:
name: trust-graph ${{ env.RELEASE_VERSION }}
tag_name: ${{ env.RELEASE_VERSION }}
files: |
trust-graph.tar.gz
./trust-graph.tar.gz
body: ${{steps.changelog.outputs.changelog}}
draft: false
prerelease: false
@ -97,10 +107,10 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
### Publish Aqua API
- name: Publish Aqua API
### Publish Aqua API
- name: Publish Aqua API to NPM
run: |
npm version ${{ env.RELEASE_VERSION }} --allow-same-version
npm version ${{ env.RELEASE_VERSION }}
npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
@ -109,9 +119,9 @@ jobs:
## Update node-distro repo
- name: Calculate SHA256
run: |
du -hs trust-graph.tar.gz
echo $(sha256sum trust-graph.tar.gz)
echo "SHA256=$(sha256sum trust-graph.tar.gz | awk '{ print $1 }')" >> $GITHUB_ENV
du -hs trust-graph.tar.gz
echo $(sha256sum trust-graph.tar.gz)
echo "SHA256=$(sha256sum trust-graph.tar.gz | awk '{ print $1 }')" >> $GITHUB_ENV
- name: Get tar.gz URL
id: package-url

89
.github/workflows/rust_ci.yml vendored Normal file
View File

@ -0,0 +1,89 @@
name: Rust CI
on:
push:
workflow_dispatch:
concurrency:
group: "${{ github.workflow }}-${{ github.ref }}"
cancel-in-progress: true
jobs:
check:
name: cargo nextest
runs-on: builder
container: rust
defaults:
run:
working-directory: service
shell: bash
steps:
- name: Checkout sources
uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: |
~/.cargo/registry
~/.cargo/git
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- run: mkdir -p ~/.bin
- run: echo "~/.bin" >> $GITHUB_PATH
- name: Install Rust
working-directory: ./service
run: |
rustup toolchain install nightly-2022-01-16-x86_64-unknown-linux-gnu
rustup default nightly-2022-01-16-x86_64-unknown-linux-gnu
rustup override set nightly-2022-01-16-x86_64-unknown-linux-gnu
rustup target add wasm32-wasi --toolchain nightly-2022-01-16-x86_64-unknown-linux-gnu
- name: Download jq
run: |
curl -L https://github.com/stedolan/jq/releases/download/jq-1.5/jq-linux64 -o ~/.bin/jq
chmod +x ~/.bin/jq
- name: Download marine
run: bash $GITHUB_WORKSPACE/.github/download_marine.sh
- name: Build
run: ./build.sh
- run: cargo install --locked cargo-nextest --version 0.9.22
- run: cargo nextest run --release --all-features --no-fail-fast --retries 10 --test-threads 10
lints:
name: Lints
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Install toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: nightly
override: true
components: rustfmt, clippy
- name: Run cargo fmt
uses: actions-rs/cargo@v1
with:
command: fmt
args: --all -- --check
- name: Run cargo clippy
uses: actions-rs/cargo@v1
with:
command: clippy
args: -Z unstable-options --all
continue-on-error: true # do not fail for now

View File

@ -10,8 +10,16 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Get branch
run: |
BRANCH=${GITHUB_REF#refs/*/}
SANITIZED=$(echo "$BRANCH" | sed -e 's/[^a-zA-Z0-9-]/-/g')
echo "BRANCH=$SANITIZED" >> $GITHUB_ENV
- name: Bump version and push tag
id: tag_version
uses: mathieudutour/github-tag-action@v5.5
with:
append_to_pre_release_tag: ${{ env.BRANCH }}
github_token: ${{ secrets.PERSONAL_TOKEN }}

2
Cargo.lock generated
View File

@ -2672,7 +2672,7 @@ dependencies = [
[[package]]
name = "trust-graph-wasm"
version = "0.3.0"
version = "0.3.1"
dependencies = [
"anyhow",
"bincode",

9337
aqua/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,7 @@
"*.aqua"
],
"dependencies": {
"@fluencelabs/aqua-lib": "^0.3.4"
"@fluencelabs/aqua-lib": "^0.5.2"
},
"scripts": {
"generate-aqua": "../service/build.sh",
@ -31,6 +31,6 @@
},
"homepage": "https://github.com/fluencelabs/trust-graph#readme",
"devDependencies": {
"@fluencelabs/aqua": "^0.5.2-257"
"@fluencelabs/aqua": "^0.7.4-322"
}
}

View File

@ -11,8 +11,9 @@ service CertOp("op"):
service TrustedComputation("op"):
identity(s: u64) -> u64
func trusted_computation(node: string) -> ?u64:
func trusted_computation(node: string) -> ?u64, ?string:
result: ?u64
error: ?string
-- on our trusted relay
on HOST_PEER_ID:
-- get all certificates issued for given node by our client's peer id
@ -20,8 +21,11 @@ func trusted_computation(node: string) -> ?u64:
if certs_result.success:
len <- CertOp.array_length(certs_result.certificates)
-- if there is any certificate node is trusted and computation is possible
if len != 0:
on node:
result <- TrustedComputation.identity(5)
<- result
if len != 0:
on node:
result <- TrustedComputation.identity(5)
else:
error <<- "there is no certs for this peer"
else:
error <<- certs_result.error
<- result, error

View File

@ -1,5 +1,6 @@
module Export
import add_root_trust, add_trust, revoke from "@fluencelabs/trust-graph/trust-graph-api.aqua"
export add_root_trust, add_trust, revoke
export add_root_trust, add_trust, revoke, timestamp_sec
import Peer from "@fluencelabs/aqua-lib/builtin.aqua"
alias PeerId: string

View File

@ -14,10 +14,10 @@
* limitations under the License.
*/
import {trusted_computation} from "./generated/computation";
import { trusted_computation } from "./generated/computation";
import * as tg from "./generated/export";
import {Fluence, FluencePeer, KeyPair} from "@fluencelabs/fluence";
import {krasnodar, Node, testNet, stage} from "@fluencelabs/fluence-network-environment";
import { Fluence, FluencePeer, KeyPair } from "@fluencelabs/fluence";
import { krasnodar, Node, testNet, stage } from "@fluencelabs/fluence-network-environment";
import assert from "assert";
const bs58 = require('bs58');
@ -42,7 +42,7 @@ let local: Node[] = [
async function revoke_all(relay: string, revoked_by: string) {
for (var node of local) {
let error = await tg.revoke(relay, revoked_by, node.peerId);
if (error === null) {
if (error !== null) {
console.log(error)
}
}
@ -51,7 +51,7 @@ async function add_root(relay: string, peer_id: string) {
let current_time = await tg.timestamp_sec();
let far_future = current_time + 9999999;
let error = await tg.add_root_trust(relay, peer_id, 2, far_future);
if (error === null) {
if (error !== null) {
console.log(error)
}
}
@ -75,12 +75,12 @@ async function revoke_checked(relay: string, revoked_by: string, revoked_peer_id
}
async function exec_trusted_computation(node: string) {
let result = await trusted_computation(node)
let [result, error] = await trusted_computation(node)
if (result !== null) {
console.log("📗 Trusted computation on node %s successful, result is %s", node, result)
} else {
console.log("📕 Trusted computation on node %s failed", node)
console.log("📕 Trusted computation on node %s failed, error:", node, error)
}
}
@ -92,7 +92,7 @@ async function main() {
let builtins_keypair = await KeyPair.fromEd25519SK(sk);
let relay = local[0];
await Fluence.start({ connectTo: relay, KeyPair: builtins_keypair});
await Fluence.start({ connectTo: relay, KeyPair: builtins_keypair });
console.log(
"📗 created a fluence peer %s with relay %s",
Fluence.getStatus().peerId,

8302
example/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -13,14 +13,14 @@
"author": "Fluence Labs",
"license": "MIT",
"dependencies": {
"@fluencelabs/aqua": "^0.5.2-257",
"@fluencelabs/aqua-lib": "^0.3.4",
"@fluencelabs/fluence": "^0.18.0",
"@fluencelabs/aqua-lib": "^0.5.2",
"@fluencelabs/fluence": "^0.23.0",
"@fluencelabs/fluence-network-environment": "^1.0.10",
"@fluencelabs/trust-graph": "file:../aqua",
"@fluencelabs/trust-graph": "3.0.2",
"bs58": "^4.0.1"
},
"devDependencies": {
"typescript": "^4.5.2"
"typescript": "^4.5.2",
"@fluencelabs/aqua": "^0.7.4-325"
}
}

View File

@ -165,7 +165,7 @@ impl TryFrom<libp2p_core::PeerId> for PublicKey {
fn try_from(peer_id: libp2p_core::PeerId) -> Result<Self, Self::Error> {
Ok(as_public_key(&peer_id)
.ok_or(DecodingError::PublicKeyNotInlined(peer_id.to_base58()))?
.ok_or_else(|| DecodingError::PublicKeyNotInlined(peer_id.to_base58()))?
.into())
}
}
@ -177,7 +177,9 @@ fn as_public_key(peer_id: &PeerId) -> Option<libp2p_core::PublicKey> {
let mhash = peer_id.as_ref();
match multihash::Code::try_from(mhash.code()) {
Ok(multihash::Code::Identity) => libp2p_core::PublicKey::from_protobuf_encoding(mhash.digest()).ok(),
Ok(multihash::Code::Identity) => {
libp2p_core::PublicKey::from_protobuf_encoding(mhash.digest()).ok()
}
_ => None,
}
}

View File

@ -1,6 +1,6 @@
[package]
name = "trust-graph-wasm"
version = "0.3.0"
version = "0.3.1"
authors = ["Fluence Labs"]
edition = "2018"
description = "trust graph wasm"

View File

@ -40,7 +40,7 @@ pub struct Certificate {
impl From<trust_graph::Certificate> for Certificate {
fn from(c: trust_graph::Certificate) -> Self {
let chain: Vec<Trust> = c.chain.into_iter().map(|t| t.into()).collect();
return Certificate { chain };
Certificate { chain }
}
}
@ -51,10 +51,10 @@ impl TryFrom<Certificate> for trust_graph::Certificate {
let chain: Result<Vec<trust_graph::Trust>, DtoConversionError> = c
.chain
.into_iter()
.map(|t| trust_graph::Trust::try_from(t))
.map(trust_graph::Trust::try_from)
.collect();
let chain = chain?;
return Ok(trust_graph::Certificate { chain });
Ok(trust_graph::Certificate { chain })
}
}
@ -85,12 +85,12 @@ impl TryFrom<Trust> for trust_graph::Trust {
let signature = Signature::from_bytes(KeyFormat::from_str(&t.sig_type)?, signature);
let expires_at = Duration::from_secs(t.expires_at);
let issued_at = Duration::from_secs(t.issued_at);
return Ok(trust_graph::Trust {
Ok(trust_graph::Trust {
issued_for,
expires_at,
signature,
issued_at,
});
})
}
}
@ -101,13 +101,13 @@ impl From<trust_graph::Trust> for Trust {
let signature = bs58::encode(raw_signature.bytes).into_string();
let expires_at = t.expires_at.as_secs();
let issued_at = t.issued_at.as_secs();
return Trust {
Trust {
issued_for,
expires_at,
signature,
sig_type: raw_signature.sig_type.into(),
issued_at,
};
}
}
}
@ -142,12 +142,12 @@ impl TryFrom<Revocation> for trust_graph::Revocation {
let signature = bs58::decode(&r.signature).into_vec()?;
let signature = Signature::from_bytes(KeyFormat::from_str(&r.sig_type)?, signature);
let revoked_at = Duration::from_secs(r.revoked_at);
return Ok(trust_graph::Revocation {
Ok(trust_graph::Revocation {
pk: revoked_pk,
revoked_at,
revoked_by: revoked_by_pk,
signature,
});
})
}
}
@ -158,12 +158,12 @@ impl From<trust_graph::Revocation> for Revocation {
let raw_signature = r.signature.get_raw_signature();
let signature = bs58::encode(raw_signature.bytes).into_string();
let revoked_at = r.revoked_at.as_secs();
return Revocation {
Revocation {
revoked_peer_id,
revoked_at,
signature,
sig_type: raw_signature.sig_type.into(),
revoked_by,
};
}
}
}

View File

@ -13,10 +13,31 @@ mod results;
mod service_api;
mod storage_impl;
mod tests;
/*
_initialize function that calls __wasm_call_ctors is required to mitigade memory leak
that is described in https://github.com/WebAssembly/wasi-libc/issues/298
In short, without this code rust wraps every export function
with __wasm_call_ctors/__wasm_call_dtors calls. This causes memory leaks. When compiler sees
an explicit call to __wasm_call_ctors in _initialize function, it disables export wrapping.
TODO: remove when updating to marine-rs-sdk with fix
*/
extern "C" {
pub fn __wasm_call_ctors();
}
#[no_mangle]
fn _initialize() {
unsafe {
__wasm_call_ctors();
}
}
//------------------------------
pub static TRUSTED_TIMESTAMP: (&str, &str) = ("peer", "timestamp_sec");
pub fn main() {
_initialize(); // As __wasm_call_ctors still does necessary work, we call it at the start of the module
WasmLoggerBuilder::new()
.with_log_level(log::LevelFilter::Trace)
.build()

View File

@ -27,10 +27,10 @@ fn set_root(peer_id: String, max_chain_len: u32) -> SetRootResult {
})
.into()
} else {
return SetRootResult {
SetRootResult {
success: false,
error: ServiceError::NotOwner.to_string(),
};
}
}
}
@ -98,7 +98,7 @@ fn get_all_certs(issued_for: String, timestamp_sec: u64) -> AllCertsResult {
fn get_all_certs_from(issued_for: String, issuer: String, timestamp_sec: u64) -> AllCertsResult {
with_tg(|tg| {
let cp = get_call_parameters();
check_timestamp_tetraplets(&cp, 1)?;
check_timestamp_tetraplets(&cp, 2)?;
get_certs_from(tg, issued_for, issuer, timestamp_sec)
})
.into()

View File

@ -272,7 +272,7 @@ impl Storage for SQLiteStorage {
statement.bind(6, &Value::Binary(relation.signature().encode()))?;
statement.next()?;
Ok({})
Ok(())
}
fn get_root_weight_factor(&self, pk: &PK) -> Result<Option<WeightFactor>, Self::Error> {
@ -309,7 +309,7 @@ impl Storage for SQLiteStorage {
])?;
cursor.next()?;
Ok({})
Ok(())
}
fn root_keys(&self) -> Result<Vec<PK>, Self::Error> {

View File

@ -887,4 +887,40 @@ mod service_tests {
assert_eq!(*trust, trusts[i].trust);
}
}
#[test]
fn test_get_all_cert_from() {
let mut trust_graph = ServiceInterface::new();
clear_env();
let (key_pairs, trusts) =
generate_trust_chain_with_len(&mut trust_graph, 5, HashMap::new());
let cur_time = current_time();
let root_peer_id = key_pairs[0].get_peer_id();
set_root_peer_id(&mut trust_graph, root_peer_id, 10);
for auth in trusts.iter() {
add_trust_checked(&mut trust_graph, auth.trust.clone(), auth.issuer, cur_time);
}
let cp = get_correct_timestamp_cp_with_host_id(
2,
key_pairs.last().unwrap().get_peer_id().to_base58(),
);
let certs = trust_graph.get_all_certs_from_cp(
key_pairs[4].get_peer_id().to_base58(),
key_pairs[3].get_peer_id().to_base58(),
cur_time,
cp,
);
assert!(certs.success, "{}", certs.error);
let certs = certs.certificates;
assert_eq!(certs.len(), 1);
assert_eq!(certs[0].chain.len(), 5);
for (i, trust) in certs[0].chain.iter().enumerate() {
assert_eq!(*trust, trusts[i].trust);
}
}
}

View File

@ -74,14 +74,26 @@ impl Certificate {
Self { chain }
}
pub fn new_from_root_trust(root_trust: Trust, issued_trust: Trust, cur_time: Duration) -> Result<Self, CertificateError> {
pub fn new_from_root_trust(
root_trust: Trust,
issued_trust: Trust,
cur_time: Duration,
) -> Result<Self, CertificateError> {
Trust::verify(&root_trust, &root_trust.issued_for, cur_time).map_err(MalformedRoot)?;
Trust::verify(&issued_trust, &root_trust.issued_for, cur_time).map_err(|e| VerificationError(1, e))?;
Trust::verify(&issued_trust, &root_trust.issued_for, cur_time)
.map_err(|e| VerificationError(1, e))?;
Ok(Self { chain: vec![root_trust, issued_trust] })
Ok(Self {
chain: vec![root_trust, issued_trust],
})
}
pub fn issue_with_trust(issued_by: PublicKey, trust: Trust, extend_cert: &Certificate, cur_time: Duration) -> Result<Self, CertificateError> {
pub fn issue_with_trust(
issued_by: PublicKey,
trust: Trust,
extend_cert: &Certificate,
cur_time: Duration,
) -> Result<Self, CertificateError> {
if trust.expires_at.lt(&trust.issued_at) {
return Err(ExpirationError {
expires_at: format!("{:?}", trust.expires_at),
@ -89,7 +101,11 @@ impl Certificate {
});
}
Certificate::verify(extend_cert, &[extend_cert.chain[0].issued_for.clone()], cur_time)?;
Certificate::verify(
extend_cert,
&[extend_cert.chain[0].issued_for.clone()],
cur_time,
)?;
// check if `issued_by` is allowed to issue a certificate (i.e., theres a trust for it in a chain)
let mut previous_trust_num: i32 = -1;
for pk_id in 0..extend_cert.chain.len() {
@ -114,7 +130,6 @@ impl Certificate {
Ok(Self { chain: new_chain })
}
/// Creates new certificate with root trust (self-signed public key) from a key pair.
#[allow(dead_code)]
pub fn issue_root(
@ -151,7 +166,11 @@ impl Certificate {
}
// first, verify given certificate
Certificate::verify(extend_cert, &[extend_cert.chain[0].issued_for.clone()], cur_time)?;
Certificate::verify(
extend_cert,
&[extend_cert.chain[0].issued_for.clone()],
cur_time,
)?;
let issued_by_pk = issued_by.public();
@ -309,7 +328,7 @@ impl FromStr for Certificate {
str_lines[i + 2],
str_lines[i + 3],
)
.map_err(|e| DecodeTrustError(i, e))?;
.map_err(|e| DecodeTrustError(i, e))?;
trusts.push(trust);
}
@ -353,7 +372,7 @@ mod tests {
cur_time,
cur_time,
)
.unwrap();
.unwrap();
let serialized = new_cert.to_string();
let deserialized = Certificate::from_str(&serialized);
@ -380,7 +399,7 @@ mod tests {
cur_time,
cur_time,
)
.unwrap();
.unwrap();
let serialized = new_cert.encode();
let deserialized = Certificate::decode(serialized.as_slice());
@ -468,7 +487,7 @@ mod tests {
cur_time.checked_sub(one_minute()).unwrap(),
cur_time,
)
.unwrap();
.unwrap();
assert!(Certificate::verify(&new_cert, &trusted_roots, cur_time).is_err());
}
@ -490,7 +509,7 @@ mod tests {
cur_time,
cur_time,
)
.unwrap();
.unwrap();
let new_cert = Certificate::issue(
&third_kp,
fourth_kp.public(),
@ -528,7 +547,7 @@ mod tests {
cur_time,
cur_time,
)
.unwrap();
.unwrap();
let new_cert = Certificate::issue(
&second_kp,
fourth_kp.public(),

View File

@ -95,7 +95,7 @@ impl From<TrustGraphError> for String {
}
fn get_weight_factor(max_chain_len: u32) -> u32 {
MAX_WEIGHT_FACTOR.checked_sub(max_chain_len).unwrap_or(0u32)
MAX_WEIGHT_FACTOR.saturating_sub(max_chain_len)
}
pub fn get_weight_from_factor(wf: WeightFactor) -> u32 {