diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 519ebd907..9f82c4ecb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -89,6 +89,7 @@ jobs: matrix: os: [ubuntu-latest, windows-latest, macos-latest] profile: [dev, release] + if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop' steps: - uses: actions/checkout@v2 - uses: dsherret/rust-toolchain-file@v1 diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index effee321b..5da46db0f 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -63,7 +63,7 @@ jobs: fi # Prebuild the program so that we can run the following script faster - export FNN="$(cargo build --message-format=json-render-diagnostics | jq -js '[.[] | select(.reason == "compiler-artifact") | select(.executable != null)] | last | .executable')" + cargo build cd tests/deploy/udt-init && cargo build && cd - if [ ${{ matrix.workflow }} = "router-pay" ]; then export START_BOOTNODE=y @@ -81,9 +81,9 @@ jobs: if [ -f $port_file ]; then break else + retry_count=$((retry_count + 1)) echo "File $port_file not found. Retrying in 2 seconds..." sleep 2 - retry_count=$((retry_count + 1)) fi done @@ -92,11 +92,15 @@ jobs: ports+=("$line") done < ./tests/nodes/.ports - for i in {1..20}; do + echo "Checking if all ports are open ... ${ports[@]}" + + try_number=60 + count=0 + while [ $count -lt $try_number ]; do all_open=true - for port in $ports; do - echo "Checking port $port" + for port in "${ports[@]}"; do if ! nc -z 127.0.0.1 $port; then + echo "Port $port is not open yet ..." all_open=false break fi @@ -105,11 +109,17 @@ jobs: echo "All ports are open now ..." break else + count=$((count + 1)) + if [ $count -eq $try_number ]; then + echo "Reached maximum number of tries ($try_number), exiting with status 1" + exit 1 + fi echo "Not all ports are open, waiting 3 seconds before retrying" sleep 3 fi done + (cd ./tests/bruno; npm exec -- @usebruno/cli@1.20.0 run e2e/${{ matrix.workflow }} -r --env ${{ matrix.test_env }} ${{ matrix.extra_bru_args }} ) & # -n means we will exit when any of the background processes exits. diff --git a/Cargo.lock b/Cargo.lock index 4049c90f9..fa35198a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1589,7 +1589,7 @@ dependencies = [ [[package]] name = "fnn" -version = "0.1.0" +version = "0.2.0" dependencies = [ "anyhow", "arcode", @@ -1621,6 +1621,7 @@ dependencies = [ "molecule", "musig2", "nom", + "num_enum", "once_cell", "ractor", "rand 0.8.5", @@ -2809,6 +2810,27 @@ dependencies = [ "autocfg", ] +[[package]] +name = "num_enum" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "number_prefix" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index 4b6d37c80..983451b07 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "fnn" -version = "0.1.0" +version = "0.2.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -63,6 +63,7 @@ tokio = { version = "1", features = [ indicatif = "0.16" console = "0.15.8" bincode = "1.3.3" +num_enum = "0.7.3" [features] default = [] diff --git a/Makefile b/Makefile index d14e3a6b1..116f1a1ff 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ GRCOV_EXCL_LINE = ^\s*(\})*(\))*(;)*$$|\s*((log::|tracing::)?(trace|debug|info|w .PHONY: test test: - RUST_LOG=off cargo nextest run --no-fail-fast + TEST_TEMP_RETAIN=1 RUST_LOG=off cargo nextest run --no-fail-fast .PHONY: clippy clippy: @@ -55,7 +55,7 @@ coverage: coverage-run-unittests coverage-collect-data coverage-generate-report .PHONY: gen-rpc-doc gen-rpc-doc: - cargo install fiber-rpc-gen + $(if $(shell command -v fiber-rpc-gen),,cargo install fiber-rpc-gen --force) fiber-rpc-gen ./src/rpc if grep -q "TODO: add desc" ./src/rpc/README.md; then \ echo "Warning: There are 'TODO: add desc' in src/rpc/README.md, please add documentation comments to resolve them"; \ diff --git a/README.md b/README.md index caf0f06f0..612e69dab 100644 --- a/README.md +++ b/README.md @@ -7,16 +7,13 @@ Fiber Network Node (FNN) is a reference implementation of Fiber Network Protocol * Payments over fiber channel (via [fiber-scripts]) * Cross-chain asset transfer -Please note that the implementation is still under development, there are two major features not implemented yet: - -* Watchtower service to monitor and revoke on-chain transactions -* Multihop payments +Please note that the implementation is still under development, there are many limitations and known issues, you may find or report them in the issue tracker. But as a prototype, it's a good starting point for developers to understand the FNP and try out the integration with their applications. ## Build and run a testnet node -1. Build the project: +1. Build the project, if you are using the released binary, you can skip this step: ``` cargo build --release @@ -26,6 +23,7 @@ cargo build --release ``` mkdir /folder-to/my-fnn +// if you are using the released binary, replace target/release/fnn with the path of released binary cp target/release/fnn /folder-to/my-fnn cp config/testnet/config.yml /folder-to/my-fnn cd /folder-to/my-fnn @@ -46,6 +44,20 @@ head -n 1 ./ckb/exported-key > ./ckb/key RUST_LOG=info ./fnn -c config.yml -d . ``` +## Testnet compatibility issues + +The current state of the FNN is not stable, the protocol and storage format may changed between versions. We strongly recommend you to close the channel before upgrading the node, otherwise, you may lose the channel state: + +1. [list all channels](./src/rpc/README.md#channel-list_channels) and [close](./src/rpc/README.md#channel-shutdown_channel) them via RPC. + +2. Stop the node and remove the storage of the node: + +``` +rm -rf /folder-to/my-fnn/fiber/store +``` + +3. Repalce the binary with the new version and start the node again. + ## Documentation * [Light Paper](./docs/light-paper.md) diff --git a/docs/specs/p2p-message.md b/docs/specs/p2p-message.md index 33f1e43e9..acaceb4b8 100644 --- a/docs/specs/p2p-message.md +++ b/docs/specs/p2p-message.md @@ -287,11 +287,19 @@ After establishing a channel, nodes can perform payment operations by sending Ad | | | | | |--(2)---- commitment_signed -->| | | |<-(3)---- revoke_and_ack -----| | + | | | | + | |<-(4)---- commitment_signed ---| | + | |--(5)---- revoke_and_ack ---->| | + | | | | | A | | B | - | |<-(4)---- remove_tlc -----| | | | | | - | |<-(5)---- commitment_signed ---| | - | |--(6)---- revoke_and_ack ---->| | + | |<-(6)---- remove_tlc -----| | + | | | | + | |<-(7)---- commitment_signed ---| | + | |--(8)---- revoke_and_ack ---->| | + | | | | + | |--(9)---- commitment_signed -->| | + | |<-(10)---- revoke_and_ack ----| | +-------+ +-------+ ``` diff --git a/src/actors.rs b/src/actors.rs index 2f2db43a2..e077e4c0d 100644 --- a/src/actors.rs +++ b/src/actors.rs @@ -1,6 +1,6 @@ use ractor::{async_trait as rasync_trait, Actor, ActorProcessingErr, ActorRef, SupervisionEvent}; use tokio_util::{sync::CancellationToken, task::TaskTracker}; -use tracing::{debug, error}; +use tracing::debug; /// A root actor that listens for cancellation token and stops all sub actors (those who started by spawn_linked). pub struct RootActor; @@ -69,7 +69,7 @@ impl Actor for RootActor { } }, SupervisionEvent::ActorPanicked(who, err) => { - error!("Actor unexpectedly panicked (id: {:?}): {:?}", who, err); + panic!("Actor unexpectedly panicked (id: {:?}): {:?}", who, err); } _ => {} } diff --git a/src/ckb/actor.rs b/src/ckb/actor.rs index 87488a9e7..2c26e7362 100644 --- a/src/ckb/actor.rs +++ b/src/ckb/actor.rs @@ -4,6 +4,7 @@ use ractor::{ concurrency::{sleep, Duration}, Actor, ActorProcessingErr, ActorRef, RpcReplyPort, }; +use tracing::debug; use crate::ckb::contracts::{get_script_by_contract, Contract}; @@ -81,7 +82,7 @@ impl Actor for CkbChainActor { async fn pre_start( &self, - myself: ActorRef, + _myself: ActorRef, config: Self::Arguments, ) -> Result { let secret_key = config.read_secret_key()?; @@ -90,12 +91,6 @@ impl Actor for CkbChainActor { let pub_key_hash = ckb_hash::blake2b_256(pub_key.serialize()); let funding_source_lock_script = get_script_by_contract(Contract::Secp256k1Lock, &pub_key_hash[0..20]); - tracing::info!( - "[{}] funding lock args: {}", - myself.get_name().unwrap_or_default(), - funding_source_lock_script.args() - ); - Ok(CkbChainState { config, secret_key, @@ -180,7 +175,7 @@ impl Actor for CkbChainActor { }, reply_port, ) => { - tracing::info!( + debug!( "[{}] trace transaction {} with {} confs", myself.get_name().unwrap_or_default(), tx_hash, diff --git a/src/ckb/config.rs b/src/ckb/config.rs index 9ddded8ec..19f50b743 100644 --- a/src/ckb/config.rs +++ b/src/ckb/config.rs @@ -1,5 +1,6 @@ +use ckb_hash::blake2b_256; use clap_serde_derive::ClapSerde; -use secp256k1::SecretKey; +use secp256k1::{Secp256k1, SecretKey}; use serde_with::serde_as; use std::{ io::{ErrorKind, Read}, @@ -13,12 +14,14 @@ use ckb_types::prelude::Pack; use ckb_types::H256; use ckb_types::{ core::DepType, - packed::{CellDep, OutPoint}, + packed::{CellDep, OutPoint, Script}, }; use clap_serde_derive::clap::{self}; use molecule::prelude::Entity; use serde::{Deserialize, Serialize}; +use super::contracts::{get_script_by_contract, Contract}; + pub const DEFAULT_CKB_BASE_DIR_NAME: &str = "ckb"; const DEFAULT_CKB_NODE_RPC_URL: &str = "http://127.0.0.1:8114"; @@ -101,6 +104,16 @@ impl CkbConfig { std::io::Error::new(ErrorKind::InvalidData, "invalid secret key data").into() }) } + + pub fn get_default_funding_lock_script(&self) -> crate::Result