diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index a6de3f2e8..000000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,84 +0,0 @@ -version: 2 -jobs: - build: - docker: - - image: circleci/rust - environment: - CARGO_HOME: /home/circleci/.cargo - resource_class: medium+ - steps: - - checkout - - restore_cache: - keys: - - cargo-cache-1-{{ checksum "Cargo.toml" }}-{{ .Branch }} - - cargo-cache-1-{{ checksum "Cargo.toml" }} - - cargo-cache-1- - - run: - name: Install Cargo Extensions - command: | - # cargo-audit started requiring libcurl3 - echo "deb http://security.ubuntu.com/ubuntu xenial-security main" | sudo tee -a /etc/apt/sources.list - sudo apt-key adv --recv-keys --keyserver keyserver.ubuntu.com 3B4FE6ACC0B21F32 - sudo apt-get update - sudo apt-get install libcurl3 -y - cargo install --quiet cargo-audit || true # cargo-kcov - rustup component add rustfmt clippy || true - - run: - name: Install Redis - command: | - sudo apt-get update - sudo apt-get install redis-server - redis-server --version - - run: - name: Reduce codegen units - # If we don't include this, the linker runs out of memory when building - # the project on CI. We don't include this normally though because - # it should be able to build with more units on other machines - command: printf "[profile.dev]\ncodegen-units = 1\n" >> Cargo.toml - - run: - name: Build - command: cargo build --all-features --all-targets - - run: - name: Test - # Note the timeout is included to make sure that they - # do not run for more than 10 minutes under any circumstances - # (We have had issues with bugs causing the tests to "run" - # for 5 hours, wasting a ton of compute credits) - command: timeout 10m cargo test --all --all-features - environment: - RUST_BACKTRACE: "1" - - run: - name: Check Style - command: | - cargo fmt --all -- --check - cargo clippy --all-targets --all-features -- -D warnings - - run: - name: Audit Dependencies - command: cargo audit - # - run: - # name: Install kcov - # command: >- - # kcov --version || - # (sudo apt-get install cmake g++ pkg-config jq libcurl4-openssl-dev libelf-dev libdw-dev binutils-dev libiberty-dev - # && cargo kcov --print-install-kcov-sh | sh) - # - run: - # name: Generate Coverage Report - # # Enable sudo to avoid the error: "Can't set personality: Operation not permitted" - # # See discussion in https://github.com/travis-ci/travis-ci/issues/9061 - # sudo: required - # command: - # cargo kcov --all --verbose - # # -- --verify - # # --exclude-region="kcov-ignore-start:kcov-ignore-end" - # # --exclude-pattern="$CARGO_HOME,**/tests/**" - # # --exclude-line="^(\)*\}*,*)$" - # environment: - # # Configure the redis tests to use a unix socket instead of TCP - # REDISRS_SERVER_TYPE: unix - # - run: - # name: Upload Code Coverage - # command: "bash <(curl -s https://codecov.io/bash)" - - save_cache: - key: cargo-cache-1-{{ checksum "Cargo.toml" }}-{{ .Branch }} - paths: - - /home/circleci/.cargo diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml new file mode 100644 index 000000000..768e32d9f --- /dev/null +++ b/.github/workflows/audit.yml @@ -0,0 +1,27 @@ +on: + pull_request: + paths-ignore: + - "docs/**/*" + - "scripts/**/*" + - "README.md" + +name: Audit Dependencies + +jobs: + audit: + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v1 + + - name: Install stable toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + + - name: Install cargo-audit + run: cargo install cargo-audit + + - name: Audit dependencies + run: cargo audit diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 000000000..bcc4c9b74 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,22 @@ +name: Build and Test + +on: + push: + paths-ignore: + - "docs/**/*" + - "scripts/**/*" + - "README.md" + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 + - name: Build + run: cargo build --all-targets --all-features + - name: Install redis + run: sudo apt install redis-server && redis-server --version + - name: Run tests + run: cargo test --all --all-features + timeout-minutes: 10 diff --git a/.github/workflows/style.yml b/.github/workflows/style.yml new file mode 100644 index 000000000..e62eff450 --- /dev/null +++ b/.github/workflows/style.yml @@ -0,0 +1,48 @@ +on: + push: + paths-ignore: + - "docs/**/*" + - "scripts/**/*" + - "README.md" + +name: Check Style + +jobs: + rustfmt: + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v1 + + - name: Install stable toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + + - name: Install rustfmt + run: rustup component add rustfmt + + - name: Run cargo fmt + uses: actions-rs/cargo@v1 + with: + command: fmt + args: --all -- --check + + clippy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - id: component + uses: actions-rs/components-nightly@v1 + with: + component: clippy + - uses: actions-rs/toolchain@v1 + with: + toolchain: ${{ steps.component.outputs.toolchain }} + override: true + - run: rustup component add clippy + - uses: actions-rs/clippy-check@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + args: --all-targets --all-features -- -D warnings diff --git a/crates/interledger-ccp/src/lib.rs b/crates/interledger-ccp/src/lib.rs index 65ba55f37..dd609c87b 100644 --- a/crates/interledger-ccp/src/lib.rs +++ b/crates/interledger-ccp/src/lib.rs @@ -12,8 +12,7 @@ use bytes::Bytes; use futures::Future; use interledger_service::Account; -use std::collections::HashMap; -use std::{str::FromStr, string::ToString}; +use std::{collections::HashMap, str::FromStr, string::ToString}; #[cfg(test)] mod fixtures; @@ -30,7 +29,7 @@ use serde::{Deserialize, Serialize}; /// Data structure used to describe the routing relation of an account with its peers. #[repr(u8)] -#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Serialize, Deserialize)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] pub enum RoutingRelation { /// An account from which we do not receive routes from, neither broadcast /// routes to diff --git a/crates/interledger-ccp/src/server.rs b/crates/interledger-ccp/src/server.rs index 7a069faac..9c56c4ee2 100644 --- a/crates/interledger-ccp/src/server.rs +++ b/crates/interledger-ccp/src/server.rs @@ -27,11 +27,11 @@ use parking_lot::{Mutex, RwLock}; use ring::digest::{digest, SHA256}; use std::collections::HashMap; use std::{ - cmp::min, + cmp::{min, Ordering}, convert::TryFrom, str, sync::{ - atomic::{AtomicU32, Ordering}, + atomic::{self, AtomicU32}, Arc, }, time::{Duration, Instant}, @@ -687,7 +687,7 @@ where .and_then(move |mut accounts| { let mut outgoing = self_clone.outgoing.clone(); let to_epoch_index = self_clone.forwarding_table.read().epoch(); - let from_epoch_index = self_clone.last_epoch_updates_sent_for.swap(to_epoch_index, Ordering::SeqCst); + let from_epoch_index = self_clone.last_epoch_updates_sent_for.swap(to_epoch_index, atomic::Ordering::SeqCst); let route_update_request = self_clone.create_route_update(from_epoch_index, to_epoch_index); @@ -933,25 +933,23 @@ fn get_best_route_for_prefix( let (best_account, best_route) = candidate_routes.fold( (account, route), |(best_account, best_route), (account, route)| { - // Prioritize child > peer > parent - if best_account.routing_relation() > account.routing_relation() { - return (best_account, best_route); - } else if best_account.routing_relation() < account.routing_relation() { - return (account, route); - } - - // Prioritize shortest path - if best_route.path.len() < route.path.len() { - return (best_account, best_route); - } else if best_route.path.len() > route.path.len() { - return (account, route); - } - - // Finally base it on account ID - if best_account.id().to_string() < account.id().to_string() { - (best_account, best_route) - } else { - (account, route) + // Priority: + // 1. child > peer > parent + // 2. shortest path + // 3. account ID (random priority) + match ( + best_account + .routing_relation() + .cmp(&account.routing_relation()), + best_route.path.len().cmp(&route.path.len()), + best_account.id().to_string().cmp(&account.id().to_string()), + ) { + (Ordering::Greater, _, _) + | (Ordering::Equal, Ordering::Less, _) + | (Ordering::Equal, Ordering::Equal, Ordering::Less) => { + (best_account, best_route) + } + _ => (account, route), } }, ); diff --git a/crates/interledger-settlement/src/test_helpers.rs b/crates/interledger-settlement/src/test_helpers.rs index bcd4fcac2..4e04eb507 100644 --- a/crates/interledger-settlement/src/test_helpers.rs +++ b/crates/interledger-settlement/src/test_helpers.rs @@ -18,8 +18,7 @@ use crate::fixtures::{BODY, MESSAGES_API, SERVICE_ADDRESS, SETTLEMENT_API, TEST_ use lazy_static::lazy_static; use parking_lot::RwLock; use std::collections::HashMap; -use std::str::FromStr; -use std::sync::Arc; +use std::{cmp::Ordering, str::FromStr, sync::Arc}; use tokio::runtime::Runtime; use url::Url; @@ -184,37 +183,41 @@ impl LeftoversStore for TestStore { ) -> Box + Send> { let mut guard = self.uncredited_settlement_amount.write(); if let Some(leftovers) = (*guard).get_mut(&account_id) { - if leftovers.1 > uncredited_settlement_amount.1 { - // the current leftovers maintain the scale so we just need to - // upscale the provided leftovers to the existing leftovers' scale - let scaled = uncredited_settlement_amount - .0 - .normalize_scale(ConvertDetails { - from: uncredited_settlement_amount.1, - to: leftovers.1, - }) - .unwrap(); - *leftovers = (leftovers.0.clone() + scaled, leftovers.1); - } else if leftovers.1 == uncredited_settlement_amount.1 { - *leftovers = ( - leftovers.0.clone() + uncredited_settlement_amount.0, - leftovers.1, - ); - } else { - // if the scale of the provided leftovers is bigger than - // existing scale then we update the scale of the leftovers' - // scale - let scaled = leftovers - .0 - .normalize_scale(ConvertDetails { - from: leftovers.1, - to: uncredited_settlement_amount.1, - }) - .unwrap(); - *leftovers = ( - uncredited_settlement_amount.0 + scaled, - uncredited_settlement_amount.1, - ); + match leftovers.1.cmp(&uncredited_settlement_amount.1) { + Ordering::Greater => { + // the current leftovers maintain the scale so we just need to + // upscale the provided leftovers to the existing leftovers' scale + let scaled = uncredited_settlement_amount + .0 + .normalize_scale(ConvertDetails { + from: uncredited_settlement_amount.1, + to: leftovers.1, + }) + .unwrap(); + *leftovers = (leftovers.0.clone() + scaled, leftovers.1); + } + Ordering::Equal => { + *leftovers = ( + leftovers.0.clone() + uncredited_settlement_amount.0, + leftovers.1, + ); + } + Ordering::Less => { + // if the scale of the provided leftovers is bigger than + // existing scale then we update the scale of the leftovers' + // scale + let scaled = leftovers + .0 + .normalize_scale(ConvertDetails { + from: leftovers.1, + to: uncredited_settlement_amount.1, + }) + .unwrap(); + *leftovers = ( + uncredited_settlement_amount.0 + scaled, + uncredited_settlement_amount.1, + ); + } } } else { (*guard).insert(account_id, uncredited_settlement_amount);