Skip to content

Commit

Permalink
End to end test with trust, verify, and check
Browse files Browse the repository at this point in the history
  • Loading branch information
erikreppel committed Apr 22, 2024
1 parent 7366c13 commit 42a7372
Showing 1 changed file with 255 additions and 0 deletions.
255 changes: 255 additions & 0 deletions tests/e2e_test.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#![cfg(test)]
mod common;

use crate::common::asserts::expect_n_connections;
use crate::common::mintpool_build::connect_all_to_first;
use alloy::hex;
use alloy::network::EthereumSigner;
use alloy::rpc::types::eth::TransactionRequest;
Expand All @@ -13,6 +15,7 @@ use alloy_signer::Signer;
use alloy_signer_wallet::LocalWallet;
use alloy_sol_types::{SolCall, SolValue};
use alloy_transport::TransportErrorKind;
use mintpool::api::admin::node_info;
use mintpool::config::{ChainInclusionMode, Config};
use mintpool::controller::{ControllerCommands, DBQuery};
use mintpool::premints::zora_premint_v2::types::IZoraPremintV2::MintArguments;
Expand Down Expand Up @@ -194,6 +197,258 @@ async fn test_zora_premint_v2_e2e() {
assert_eq!(all_premints.len(), 0);
}

// Spin up 2 nodes, one in check, one in verify, confirm that after the check node sees something onchain the verify node also will
#[test_log::test(tokio::test)]
async fn test_verify_e2e() {
let fork_block = 13253646;
let anvil = Anvil::new()
.chain_id(7777777)
.fork_block_number(fork_block)
.fork("https://rpc.zora.energy")
.spawn();

let config1 = Config {
seed: 0,
peer_port: 7778,
connect_external: false,
db_url: None,
persist_state: false,
prune_minted_premints: false, // important so we can query table
api_port: 0,
peer_limit: 10,
supported_premint_types: "zora_premint_v2".to_string(),
chain_inclusion_mode: ChainInclusionMode::Check,
supported_chain_ids: "7777777".to_string(),
trusted_peers: None,
node_id: None,
external_address: None,
interactive: false,
enable_rpc: true,
admin_api_secret: None,
rate_limit_rps: 1,
};

let config2 = Config {
seed: 1,
peer_port: 7779,
connect_external: false,
db_url: None,
persist_state: false,
prune_minted_premints: false, // important so we can query table
api_port: 0,
peer_limit: 10,
supported_premint_types: "zora_premint_v2".to_string(),
chain_inclusion_mode: ChainInclusionMode::Verify,
supported_chain_ids: "7777777".to_string(),
trusted_peers: None,
node_id: None,
external_address: None,
interactive: false,
enable_rpc: true,
admin_api_secret: None,
rate_limit_rps: 1,
};

env::set_var("CHAIN_7777777_RPC_WSS", anvil.ws_endpoint());

// ============================================================================================
// Start 3 nodes, one in check, one in verify, one in trust (trusts node 1)
// ============================================================================================

let ctl1 = run::start_p2p_services(&config1, RulesEngine::new_with_default_rules(&config1))
.await
.unwrap();
run::start_watch_chain::<ZoraPremintV2>(&config1, ctl1.clone()).await;

let ctl2 = run::start_p2p_services(&config2, RulesEngine::new_with_default_rules(&config2))
.await
.unwrap();

let (snd, rcv) = tokio::sync::oneshot::channel();
ctl1.send_command(ControllerCommands::ReturnNetworkState { channel: snd })
.await
.unwrap();
let node_info = rcv.await.unwrap();

let config3 = Config {
seed: 2,
peer_port: 7776,
connect_external: false,
db_url: None,
persist_state: false,
prune_minted_premints: false, // important so we can query table
api_port: 0,
peer_limit: 10,
supported_premint_types: "zora_premint_v2".to_string(),
chain_inclusion_mode: ChainInclusionMode::Verify,
supported_chain_ids: "7777777".to_string(),
trusted_peers: Some(node_info.local_peer_id.to_string()),
node_id: None,
external_address: None,
interactive: false,
enable_rpc: true,
admin_api_secret: None,
rate_limit_rps: 1,
};

let ctl3 = run::start_p2p_services(&config3, RulesEngine::new_with_default_rules(&config3))
.await
.unwrap();

connect_all_to_first(vec![ctl1.clone(), ctl2.clone(), ctl3.clone()]).await;

expect_n_connections(&ctl1, 2).await;

tokio::time::sleep(Duration::from_millis(300)).await;

// ============================================================================================
// Publish a premint to the mintpool
// ============================================================================================
let premint: ZoraPremintV2 = serde_json::from_str(PREMINT_JSON).unwrap();

let (send, recv) = tokio::sync::oneshot::channel();
ctl1.send_command(ControllerCommands::Broadcast {
message: PremintTypes::ZoraV2(premint),
channel: send,
})
.await
.unwrap();
recv.await.unwrap().unwrap();

// Read the premint from DB, expect there to be 1 in each
let (send, recv) = tokio::sync::oneshot::channel();
ctl1.send_command(ControllerCommands::Query(DBQuery::ListAll(send)))
.await
.unwrap();
let all_premints = recv.await.unwrap().unwrap();
assert_eq!(all_premints.len(), 1);

let (send, recv) = tokio::sync::oneshot::channel();
ctl2.send_command(ControllerCommands::Query(DBQuery::ListAll(send)))
.await
.unwrap();
let all_premints = recv.await.unwrap().unwrap();
assert_eq!(all_premints.len(), 1);

let (send, recv) = tokio::sync::oneshot::channel();
ctl3.send_command(ControllerCommands::Query(DBQuery::ListAll(send)))
.await
.unwrap();
let all_premints = recv.await.unwrap().unwrap();
assert_eq!(all_premints.len(), 1);

// ============================================================================================
// query for message from mintpool
// ============================================================================================

let found = all_premints.first().unwrap();
let premint = match found {
PremintTypes::ZoraV2(premint) => premint,
_ => panic!("unexpected premint type"),
};

// ============================================================================================
// bring premint onchain
// ============================================================================================

let signer: LocalWallet = anvil.keys()[0].clone().into();
let signer = signer.with_chain_id(Some(7777777));

let provider = ProviderBuilder::new()
.with_recommended_layers()
.signer(EthereumSigner::from(signer.clone()))
.on_client(RpcClient::new_http(anvil.endpoint_url()));

let calldata = {
let s = premint.clone().signature;
let h = hex::decode(s).unwrap();
let sig = Bytes::from(h);
IZoraPremintV2::premintV2Call {
contractConfig: premint.clone().collection,
premintConfig: premint.clone().premint,
signature: sig,
quantityToMint: U256::from(1),
mintArguments: MintArguments {
mintRecipient: signer.address(),
mintComment: "".to_string(),
mintRewardsRecipients: vec![],
},
}
};

let gas_price = provider.get_gas_price().await.unwrap();
let max_fee_per_gas = provider.get_max_priority_fee_per_gas().await.unwrap();

let value: u64 = 777_000_000_000_000;
// Someone found the premint and brought it onchain
let tx_request = TransactionRequest {
from: Some(signer.address()),
to: Some(PREMINT_FACTORY_ADDR),
input: Some(Bytes::from(calldata.abi_encode())).into(),
value: Some(U256::from(value)),
chain_id: Some(7777777),
gas_price: Some(gas_price),
max_fee_per_gas: Some(max_fee_per_gas),
..Default::default()
};

fn map_call_error(err: RpcError<TransportErrorKind>) -> String {
match err {
RpcError::ErrorResp(err) => {
println!("Error: {:?}", err.clone());
let b = err.clone().data.unwrap();

let msg =
IZoraPremintV2::premintV2Call::abi_decode_returns(&b.get().abi_encode(), false)
.unwrap();
format!("Error: {:?}, returns: {:?}", err, msg)
}
_ => {
format!("unexpected error, could not parse: {:?}", err)
}
}
}

let tx = provider.send_transaction(tx_request).await;
let tx = match tx {
Ok(tx) => tx,
Err(e) => panic!("{}", map_call_error(e)),
};

match tx.get_receipt().await {
Ok(_receipt) => {
println!("receipt found");
}
Err(e) => panic!("{}", map_call_error(e)),
}
tokio::time::sleep(Duration::from_secs(1)).await;

// ============================================================================================
// Confirm is either marked as pruned or removed from both DB
// node2 should have pruned using verify
// ============================================================================================
let (send, recv) = tokio::sync::oneshot::channel();
ctl1.send_command(ControllerCommands::Query(DBQuery::ListAll(send)))
.await
.unwrap();
let all_premints = recv.await.unwrap().unwrap();
assert_eq!(all_premints.len(), 0);

let (send, recv) = tokio::sync::oneshot::channel();
ctl2.send_command(ControllerCommands::Query(DBQuery::ListAll(send)))
.await
.unwrap();
let all_premints = recv.await.unwrap().unwrap();
assert_eq!(all_premints.len(), 0);

let (send, recv) = tokio::sync::oneshot::channel();
ctl3.send_command(ControllerCommands::Query(DBQuery::ListAll(send)))
.await
.unwrap();
let all_premints = recv.await.unwrap().unwrap();
assert_eq!(all_premints.len(), 0);
}

const PREMINT_JSON: &str = r#"
{
"collection": {
Expand Down

0 comments on commit 42a7372

Please sign in to comment.