Skip to content
This repository has been archived by the owner on Jan 11, 2024. It is now read-only.

Commit

Permalink
Test staking: Part 2 (#319)
Browse files Browse the repository at this point in the history
* TEST: Use EthAddress

* TEST: Update closure

* TEST: Generate join and leave

* TEST: Separate configuration number for current and next

* TEST: Take &mut self in StakingState

* TEST: Test join

* TEST: Test collateral and balance

* TEST: Test stake command; fix check of has_joined

* TEST: Test leave command; fix total collateral

* TEST: Test checkpoint command; signature fails

* TEST: Build checkpoint during command run

* TEST: Higher default random size

* TEST: Unit test for ABI encoding

* TEST: Hash checkpoint as tuple

* TEST: Try sending the signature with +27 recovery ID

* TEST: Use non-masked ethereum address

* TEST: Do not increment config when staking 0

* TEST: Tweak token amount generation so there aren't that many zeroes

* TEST: Choose min_collateral so the last joiner activates

* TEST: Bootstrap tests

* TEST: Claim

* TEST: Show error data in genesis

* TEST: min_collateral > 0

* TEST: use local actors

* TEST: Ranking

* TEST: Subnet deactivation

* TEST: Trying to debug the active validator set

* TEST: See doesn't need bytes

* TEST: Do not fail test if minimum collateral disagrees

* TEST: Maybe we should fail

* TEST: Assert active limit

* TEST: Fix repeatability

* TEST: Example of going over the limit of 2 active validators

* TEST: Debugged the over-the-limit validators

* TEST: Fix the active collateral sum

* TEST: Quit testing if we hit the situation of differently ordered minimum collaterals

* TEST: Check the hash of cross messages

* TEST: Point at the integration testing branch of ABIs

* TEST: Fix clippy

* TEST: Update ABI git reference

* FIX: Only take the /out

* FIX: Install openssl in docker

* TEST: Update Rust version in docker

* FIX: Remove debug

* FIX: 27 shift only needed by Solidity

* TEST: Add unstake

* FIX: SMT unit tests

* FIX: Update RocksDB code

* TEST: Use IPC actors dev
  • Loading branch information
aakoshh authored Oct 25, 2023
1 parent b1dc6c1 commit 66ca42d
Show file tree
Hide file tree
Showing 27 changed files with 1,513 additions and 364 deletions.
282 changes: 158 additions & 124 deletions Cargo.lock

Large diffs are not rendered by default.

8 changes: 6 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ url = "2.4.1"
# Using the 3.3 version of the FVM because the newer ones update the IPLD dependencies
# to version which are different than the ones in the builtin-actors project, and since
# they are 0.x cargo cannot upgrade them automatically, which leads to version conflicts.
fvm = { version = "~3.2", default-features = false } # no opencl feature or it fails on CI
fvm = { version = "~3.2", default-features = false } # no opencl feature or it fails on CI
fvm_shared = { version = "~3.2", features = ["crypto"] }
primitives = { git = "https://github.com/consensus-shipyard/fvm-utils" }

Expand Down Expand Up @@ -130,8 +130,9 @@ tendermint-proto = { version = "0.31" }

ipc-sdk = { git = "https://github.com/consensus-shipyard/ipc.git", branch = "dev" }
ipc_ipld_resolver = { git = "https://github.com/consensus-shipyard/ipc-ipld-resolver.git", branch = "main" }
ipc_actors_abis = { git = "https://github.com/consensus-shipyard/ipc-solidity-actors.git", branch = "dev" }
ipc-provider = { git = "https://github.com/consensus-shipyard/ipc.git", branch = "dev" }
# NOTE: If you change the branch here make sure to change IPC_ACTORS_TAG in the Makefile as well.
ipc_actors_abis = { git = "https://github.com/consensus-shipyard/ipc-solidity-actors.git", branch = "dev" }

[patch.crates-io]
# Use stable-only features.
Expand All @@ -144,3 +145,6 @@ merkle-tree-rs = { git = "https://github.com/consensus-shipyard/merkle-tree-rs.g
# [patch."https://github.com/consensus-shipyard/ipc"]
# ipc-sdk = { path = "../ipc/ipc/sdk" }
# ipc-provider = { path = "../ipc/ipc/provider" }

# [patch."https://github.com/consensus-shipyard/ipc-solidity-actors.git"]
# ipc_actors_abis = { path = "../ipc-solidity-actors/binding" }
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ IPC_ACTORS_CODE := $(shell find $(shell $(IPC_ACTORS_FIND)) -type f -name
IPC_ACTORS_ABI := .make/.ipc-actors-abi
# Note that without `:=`, just `=`, it should evaluate it every time it appears in a target.
IPC_ACTORS_DIR = $(shell $(IPC_ACTORS_FIND))
IPC_ACTORS_OUT = $(shell find $(IPC_ACTORS_DIR) -type d -name out)
IPC_ACTORS_OUT = $(IPC_ACTORS_DIR)/out

FENDERMINT_CODE := $(shell find . -type f \( -name "*.rs" -o -name "Cargo.toml" \) | grep -v target)

Expand Down
2 changes: 1 addition & 1 deletion docker/ci.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
FROM ubuntu:latest

RUN apt-get update && \
apt-get install -y libstdc++6 && \
apt-get install -y libstdc++6 openssl && \
rm -rf /var/lib/apt/lists/*

ENV FM_HOME_DIR=/fendermint
Expand Down
2 changes: 1 addition & 1 deletion docker/local.Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# syntax=docker/dockerfile:1

# Builder
FROM rust:1.69 as builder
FROM rust:1.73 as builder

RUN apt-get update && \
apt-get install -y build-essential clang cmake protobuf-compiler && \
Expand Down
3 changes: 2 additions & 1 deletion fendermint/eth/api/src/conv/from_tm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,8 @@ pub fn to_eth_transaction(
hash: et::TxHash,
) -> anyhow::Result<et::Transaction> {
// Based on https://github.com/filecoin-project/lotus/blob/6cc506f5cf751215be6badc94a960251c6453202/node/impl/full/eth.go#L2048
let sig = to_eth_signature(msg.signature()).context("failed to convert to eth signature")?;
let sig =
to_eth_signature(msg.signature(), true).context("failed to convert to eth signature")?;
let msg = msg.message;

let tx = et::Transaction {
Expand Down
2 changes: 1 addition & 1 deletion fendermint/rocksdb/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ license.workspace = true

[dependencies]
num_cpus = "1.14"
rocksdb = { version = "0.19", features = ["multi-threaded-cf"] }
rocksdb = { version = "0.21", features = ["multi-threaded-cf"] }
anyhow = { workspace = true }
fendermint_storage = { path = "../storage", optional = true, features = ["testing"] }
serde = { workspace = true }
Expand Down
2 changes: 1 addition & 1 deletion fendermint/rocksdb/src/rocks/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ impl From<&RocksDbConfig> for Options {
opts.set_data_block_index_type(DataBlockIndexType::BinaryAndHash);
opts.set_data_block_hash_ratio(0.75);
opts.set_bloom_filter(10.0, false);
let cache = Cache::new_lru_cache(cache_size * 1024 * 1024).unwrap();
let cache = Cache::new_lru_cache(cache_size * 1024 * 1024);
opts.set_block_cache(&cache);
db_opts.set_block_based_table_factory(&opts);
db_opts.set_memtable_prefix_bloom_ratio(0.02);
Expand Down
4 changes: 2 additions & 2 deletions fendermint/testing/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ hex = { workspace = true, optional = true }
lazy_static = { workspace = true }
num-bigint = { workspace = true, optional = true }
quickcheck = { workspace = true, optional = true }
arbtest = { workspace = true, optional = true }
rand = { workspace = true, optional = true }

cid = { workspace = true, optional = true }
Expand All @@ -25,14 +26,13 @@ fvm_shared = { workspace = true, optional = true, features = ["arb"] }
ipc-sdk = { workspace = true, optional = true }

[dev-dependencies]
arbtest = { workspace = true }
arbitrary = { workspace = true }

fendermint_testing = { path = ".", features = ["smt"] }

[features]
default = []
smt = ["arbitrary"]
smt = ["arbitrary", "arbtest"]
golden = ["quickcheck", "hex", "serde", "serde_json", "cid", "fvm_ipld_encoding"]
arb = [
"quickcheck",
Expand Down
1 change: 1 addition & 0 deletions fendermint/testing/contract-test/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ ethers = { workspace = true }
fvm = { workspace = true }
fvm_shared = { workspace = true }
fvm_ipld_blockstore = { workspace = true }
hex = { workspace = true }
rand = { workspace = true }
tendermint-rpc = { workspace = true }

Expand Down
2 changes: 1 addition & 1 deletion fendermint/testing/contract-test/src/ipc/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ impl<DB> RegistryCaller<DB> {
pub fn new(actor_id: ActorID) -> Self {
let addr = EthAddress::from_id(actor_id);
Self {
addr,
addr: addr.into_non_masked(),
registry: ContractCaller::new(addr, SubnetRegistry::new),
_getter: ContractCaller::new(addr, SubnetActorGetterFacet::new),
_manager: ContractCaller::new(addr, SubnetActorManagerFacet::new),
Expand Down
159 changes: 153 additions & 6 deletions fendermint/testing/contract-test/src/ipc/subnet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,31 @@
use fendermint_vm_actor_interface::eam::EthAddress;
use fendermint_vm_actor_interface::ipc::subnet::SubnetActorErrors;
use fendermint_vm_genesis::{Collateral, Validator};
use fendermint_vm_interpreter::fvm::state::fevm::{ContractCaller, MockProvider, NoRevert};
use fendermint_vm_interpreter::fvm::state::fevm::{
ContractCaller, ContractResult, MockProvider, NoRevert,
};
use fendermint_vm_interpreter::fvm::state::FvmExecState;
use fendermint_vm_message::conv::from_fvm;
use fendermint_vm_message::conv::{from_eth, from_fvm};
use fvm_ipld_blockstore::Blockstore;
use ipc_actors_abis::subnet_actor_getter_facet::SubnetActorGetterFacet;
use ipc_actors_abis::subnet_actor_manager_facet::SubnetActorManagerFacet;
use fvm_shared::crypto::signature::SECP_SIG_LEN;
use fvm_shared::econ::TokenAmount;
use ipc_actors_abis::subnet_actor_getter_facet::{self as getter, SubnetActorGetterFacet};
use ipc_actors_abis::subnet_actor_manager_facet::{self as manager, SubnetActorManagerFacet};

pub use ipc_actors_abis::subnet_registry::ConstructorParams as SubnetConstructorParams;

#[derive(Clone)]
pub struct SubnetCaller<DB> {
addr: EthAddress,
_getter: ContractCaller<DB, SubnetActorGetterFacet<MockProvider>, NoRevert>,
getter: ContractCaller<DB, SubnetActorGetterFacet<MockProvider>, NoRevert>,
manager: ContractCaller<DB, SubnetActorManagerFacet<MockProvider>, SubnetActorErrors>,
}

impl<DB> SubnetCaller<DB> {
pub fn new(addr: EthAddress) -> Self {
Self {
addr,
_getter: ContractCaller::new(addr, SubnetActorGetterFacet::new),
getter: ContractCaller::new(addr, SubnetActorGetterFacet::new),
manager: ContractCaller::new(addr, SubnetActorManagerFacet::new),
}
}
Expand All @@ -34,6 +38,8 @@ impl<DB> SubnetCaller<DB> {
}
}

type TryCallResult<T> = anyhow::Result<ContractResult<T, SubnetActorErrors>>;

impl<DB: Blockstore> SubnetCaller<DB> {
/// Join a subnet as a validator.
pub fn join(
Expand All @@ -50,4 +56,145 @@ impl<DB: Blockstore> SubnetCaller<DB> {
c.join(public_key.into()).from(addr).value(deposit)
})
}

/// Try to join the subnet as a validator.
pub fn try_join(
&self,
state: &mut FvmExecState<DB>,
validator: &Validator<Collateral>,
) -> TryCallResult<()> {
let public_key = validator.public_key.0.serialize();
let addr = EthAddress::new_secp256k1(&public_key)?;
let deposit = from_fvm::to_eth_tokens(&validator.power.0)?;
self.manager.try_call(state, |c| {
c.join(public_key.into()).from(addr).value(deposit)
})
}

/// Try to increase the stake of a validator.
pub fn try_stake(
&self,
state: &mut FvmExecState<DB>,
addr: &EthAddress,
value: &TokenAmount,
) -> TryCallResult<()> {
let deposit = from_fvm::to_eth_tokens(value)?;
self.manager
.try_call(state, |c| c.stake().from(addr).value(deposit))
}

/// Try to decrease the stake of a validator.
pub fn try_unstake(
&self,
state: &mut FvmExecState<DB>,
addr: &EthAddress,
value: &TokenAmount,
) -> TryCallResult<()> {
let withdraw = from_fvm::to_eth_tokens(value)?;
self.manager
.try_call(state, |c| c.unstake(withdraw).from(addr))
}

/// Try to remove all stake of a validator.
pub fn try_leave(&self, state: &mut FvmExecState<DB>, addr: &EthAddress) -> TryCallResult<()> {
self.manager.try_call(state, |c| c.leave().from(addr))
}

/// Claim any refunds.
pub fn try_claim(&self, state: &mut FvmExecState<DB>, addr: &EthAddress) -> TryCallResult<()> {
self.manager.try_call(state, |c| c.claim().from(addr))
}

/// Submit a bottom-up checkpoint.
pub fn try_submit_checkpoint(
&self,
state: &mut FvmExecState<DB>,
checkpoint: manager::BottomUpCheckpoint,
messages: Vec<manager::CrossMsg>,
signatures: Vec<(EthAddress, [u8; SECP_SIG_LEN])>,
) -> TryCallResult<()> {
let mut addrs = Vec::new();
let mut sigs = Vec::new();
for (addr, sig) in signatures {
addrs.push(addr.into());
sigs.push(sig.into());
}
self.manager.try_call(state, |c| {
c.submit_checkpoint(checkpoint, messages, addrs, sigs)
})
}

/// Get information about the validator's current and total collateral.
pub fn get_validator(
&self,
state: &mut FvmExecState<DB>,
addr: &EthAddress,
) -> anyhow::Result<getter::ValidatorInfo> {
self.getter.call(state, |c| c.get_validator(addr.into()))
}

/// Get the confirmed collateral of a validator.
pub fn confirmed_collateral(
&self,
state: &mut FvmExecState<DB>,
addr: &EthAddress,
) -> anyhow::Result<TokenAmount> {
self.get_validator(state, addr)
.map(|i| from_eth::to_fvm_tokens(&i.confirmed_collateral))
}

/// Get the total (unconfirmed) collateral of a validator.
pub fn total_collateral(
&self,
state: &mut FvmExecState<DB>,
addr: &EthAddress,
) -> anyhow::Result<TokenAmount> {
self.get_validator(state, addr)
.map(|i| from_eth::to_fvm_tokens(&i.total_collateral))
}

/// Get the `(next, start)` configuration number pair.
///
/// * `next` is the next expected one
/// * `start` is the first unapplied one
pub fn get_configuration_numbers(
&self,
state: &mut FvmExecState<DB>,
) -> anyhow::Result<(u64, u64)> {
self.getter.call(state, |c| c.get_configuration_numbers())
}

/// Check if minimum collateral has been met.
pub fn bootstrapped(&self, state: &mut FvmExecState<DB>) -> anyhow::Result<bool> {
self.getter.call(state, |c| c.bootstrapped())
}

/// Check if a validator is active, ie. they are in the top N.
pub fn is_active(
&self,
state: &mut FvmExecState<DB>,
addr: &EthAddress,
) -> anyhow::Result<bool> {
self.getter
.call(state, |c| c.is_active_validator(addr.into()))
}

/// Check if a validator is wating, ie. they have deposited but are not in the top N.
pub fn is_waiting(
&self,
state: &mut FvmExecState<DB>,
addr: &EthAddress,
) -> anyhow::Result<bool> {
self.getter
.call(state, |c| c.is_waiting_validator(addr.into()))
}

/// This is purely for testing, although we could use it in production to avoid having to match Rust and Solidity semantics.
pub fn cross_msgs_hash(
&self,
state: &mut FvmExecState<DB>,
cross_msgs: Vec<getter::CrossMsg>,
) -> anyhow::Result<[u8; 32]> {
self.getter.call(state, |c| c.cross_msgs_hash(cross_msgs))
}
}
Loading

0 comments on commit 66ca42d

Please sign in to comment.