Skip to content

Commit

Permalink
fully compilable refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
EricBolten committed Nov 20, 2021
1 parent 6939cc6 commit c72e123
Show file tree
Hide file tree
Showing 12 changed files with 246 additions and 209 deletions.
3 changes: 3 additions & 0 deletions orchestrator/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 28 additions & 0 deletions orchestrator/ethereum_gravity/src/erc20_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,32 @@ pub async fn get_erc20_balance(
let contract_call = erc20_contract.balance_of(address);

Ok(contract_call.call().await?)
}

// TODO(bolten): is this dead code?
pub async fn erc20_transfer(
erc20: Address,
destination: Address,
amount: U256,
eth_client: EthClient,
) -> Result<TxHash, GravityError> {
let erc20_contract = ERC20::new(erc20, eth_client.clone());
let contract_call = erc20_contract.transfer(destination, amount);

let pending_tx = contract_call.send().await?;
let tx_hash = *pending_tx;
info!("Transferring {} ERC-20 {} from {} to {} with txid {}",
amount, erc20, eth_client.address(), destination, tx_hash
);
// TODO(bolten): ethers interval default is 7s, this mirrors what web30 was doing, should we adjust?
// additionally we are mirroring only waiting for 1 confirmation by leaving that as default
let pending_tx = pending_tx.interval(Duration::from_secs(1));
let potential_error = GravityError::GravityContractError(format!(
"Did not receive transaction receipt when transferring ERC-20 {}: {}", erc20, tx_hash)
);

match pending_tx.await? {
Some(receipt) => Ok(receipt.transaction_hash),
None => Err(potential_error)
}
}
3 changes: 3 additions & 0 deletions orchestrator/test_runner/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ edition = "2018"
[dependencies]
ethereum_gravity = {path = "../ethereum_gravity"}
cosmos_gravity = {path = "../cosmos_gravity"}
gravity_abi = { path = "../gravity_abi" }
gravity_utils = {path = "../gravity_utils"}
gravity_proto = {path = "../gravity_proto/"}
orchestrator = {path = "../orchestrator/"}
Expand All @@ -20,6 +21,7 @@ deep_space ={git="https://github.com/iqlusioninc/deep_space/", branch="master"}
serde_derive = "1.0"
clarity = "0.4.11"
docopt = "1"
ethers = "0.5.4"
serde = "1.0"
actix = "0.11"
actix-web = {version = "3", features=["openssl"]}
Expand All @@ -33,3 +35,4 @@ tokio = "1.4.0"
rand = "0.8"
tonic = "0.4"
futures = "0.3"
hex = "0.4.3"
4 changes: 2 additions & 2 deletions orchestrator/test_runner/src/arbitrary_logic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@

use crate::TOTAL_TIMEOUT;
use deep_space::Contact;
use ethers::prelude::*;
use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient;
use tokio::time::sleep as delay_for;
use tonic::transport::Channel;
use web30::client::Web3;

pub async fn arbitrary_logic_test(
_web30: &Web3,
_eth_provider: &Provider<Http>,
_grpc_client: GravityQueryClient<Channel>,
_contact: &Contact,
) {
Expand Down
9 changes: 5 additions & 4 deletions orchestrator/test_runner/src/bootstrapping.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
use crate::utils::ValidatorKeys;
use clarity::Address as EthAddress;
use clarity::PrivateKey as EthPrivateKey;
use ethers::core::k256::ecdsa::SigningKey;
use ethers::types::Address as EthAddress;
use deep_space::private_key::PrivateKey as CosmosPrivateKey;
use std::fs::File;
use std::io::{BufRead, BufReader, Read};

pub fn parse_ethereum_keys() -> Vec<EthPrivateKey> {
pub fn parse_ethereum_keys() -> Vec<SigningKey> {
let filename = "/testdata/validator-eth-keys";
let file = File::open(filename).expect("Failed to find eth keys");
let reader = BufReader::new(file);
let mut ret = Vec::new();

for line in reader.lines() {
let line = line.expect("Error reading eth-keys file!");
let key: EthPrivateKey = line.parse().unwrap();
let key_hex = hex::decode(line.strip_prefix("0x").unwrap()).unwrap();
let key: SigningKey = SigningKey::from_bytes(&key_hex).unwrap();
ret.push(key);
}
ret
Expand Down
96 changes: 45 additions & 51 deletions orchestrator/test_runner/src/happy_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,32 @@ use crate::get_fee;
use crate::get_gas_price;
use crate::utils::*;
use crate::MINER_ADDRESS;
use crate::MINER_PRIVATE_KEY;
use crate::MINER_CLIENT;
use crate::OPERATION_TIMEOUT;
use crate::TOTAL_TIMEOUT;
use clarity::PrivateKey as EthPrivateKey;
use clarity::{Address as EthAddress, Uint256};
use clarity::Uint256;
use cosmos_gravity::send::{send_request_batch_tx, send_to_eth};
use cosmos_gravity::{build, query::get_oldest_unsigned_transaction_batch, send};
use deep_space::address::Address as CosmosAddress;
use deep_space::coin::Coin;
use deep_space::private_key::PrivateKey as CosmosPrivateKey;
use deep_space::Contact;
use ethereum_gravity::erc20_utils::get_erc20_balance;
use ethereum_gravity::utils::get_valset_nonce;
use ethereum_gravity::{send_to_cosmos::send_to_cosmos, utils::get_tx_batch_nonce};
use ethers::core::k256::ecdsa::SigningKey;
use ethers::prelude::*;
use ethers::types::Address as EthAddress;
use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient;
use gravity_utils::types::SendToCosmosEvent;
use rand::Rng;
use std::str::FromStr;
use std::time::Duration;
use std::time::Instant;
use tokio::time::sleep as delay_for;
use tonic::transport::Channel;
use web30::client::Web3;

pub async fn happy_path_test(
web30: &Web3,
grpc_client: GravityQueryClient<Channel>,
contact: &Contact,
keys: Vec<ValidatorKeys>,
Expand All @@ -49,10 +51,10 @@ pub async fn happy_path_test(

if !validator_out {
for _ in 0u32..2 {
test_valset_update(&web30, contact, &keys, gravity_address).await;
test_valset_update(contact, &keys, gravity_address).await;
}
} else {
wait_for_nonzero_valset(&web30, gravity_address).await;
wait_for_nonzero_valset(gravity_address).await;
}

// generate an address for coin sending tests, this ensures test imdepotency
Expand All @@ -62,15 +64,15 @@ pub async fn happy_path_test(
let dest_cosmos_address = dest_cosmos_private_key
.to_address(CosmosAddress::DEFAULT_PREFIX)
.unwrap();
let dest_eth_private_key = EthPrivateKey::from_slice(&secret).unwrap();
let dest_eth_address = dest_eth_private_key.to_public_key().unwrap();
let dest_eth_private_key = SigningKey::from_bytes(&secret).unwrap();
let dest_eth_wallet = LocalWallet::from(dest_eth_private_key.clone());
let dest_eth_address = dest_eth_wallet.address();

// the denom and amount of the token bridged from Ethereum -> Cosmos
// so the denom is the gravity<hash> token name
// Send a token 3 times
for _ in 0u32..3 {
test_erc20_deposit(
&web30,
&contact,
dest_cosmos_address,
gravity_address,
Expand Down Expand Up @@ -98,7 +100,6 @@ pub async fn happy_path_test(
test_batch(
&contact,
&mut grpc_client,
&web30,
dest_eth_address,
gravity_address,
keys[0].validator_key,
Expand All @@ -108,15 +109,15 @@ pub async fn happy_path_test(
.await;
}

pub async fn wait_for_nonzero_valset(web30: &Web3, gravity_address: EthAddress) {
pub async fn wait_for_nonzero_valset(gravity_address: EthAddress) {
let start = Instant::now();
let mut current_eth_valset_nonce = get_valset_nonce(gravity_address, *MINER_ADDRESS, &web30)
let mut current_eth_valset_nonce = get_valset_nonce(gravity_address, (*MINER_CLIENT).clone())
.await
.expect("Failed to get current eth valset");

while 0 == current_eth_valset_nonce {
info!("Validator set is not yet updated to >0, waiting");
current_eth_valset_nonce = get_valset_nonce(gravity_address, *MINER_ADDRESS, &web30)
current_eth_valset_nonce = get_valset_nonce(gravity_address, (*MINER_CLIENT).clone())
.await
.expect("Failed to get current eth valset");
delay_for(Duration::from_secs(4)).await;
Expand All @@ -127,14 +128,13 @@ pub async fn wait_for_nonzero_valset(web30: &Web3, gravity_address: EthAddress)
}

pub async fn test_valset_update(
web30: &Web3,
contact: &Contact,
keys: &[ValidatorKeys],
gravity_address: EthAddress,
) {
// if we don't do this the orchestrators may run ahead of us and we'll be stuck here after
// getting credit for two loops when we did one
let starting_eth_valset_nonce = get_valset_nonce(gravity_address, *MINER_ADDRESS, &web30)
let starting_eth_valset_nonce = get_valset_nonce(gravity_address, (*MINER_CLIENT).clone())
.await
.expect("Failed to get starting eth valset");
let start = Instant::now();
Expand Down Expand Up @@ -197,7 +197,7 @@ pub async fn test_valset_update(
break;
}

let mut current_eth_valset_nonce = get_valset_nonce(gravity_address, *MINER_ADDRESS, &web30)
let mut current_eth_valset_nonce = get_valset_nonce(gravity_address, (*MINER_CLIENT).clone())
.await
.expect("Failed to get current eth valset");

Expand All @@ -206,7 +206,7 @@ pub async fn test_valset_update(
"Validator set is not yet updated to >{}, waiting",
starting_eth_valset_nonce
);
current_eth_valset_nonce = get_valset_nonce(gravity_address, *MINER_ADDRESS, &web30)
current_eth_valset_nonce = get_valset_nonce(gravity_address, (*MINER_CLIENT).clone())
.await
.expect("Failed to get current eth valset");
delay_for(Duration::from_secs(4)).await;
Expand All @@ -221,13 +221,13 @@ pub async fn test_valset_update(

/// this function tests Ethereum -> Cosmos
async fn test_erc20_deposit(
web30: &Web3,
contact: &Contact,
dest: CosmosAddress,
gravity_address: EthAddress,
erc20_address: EthAddress,
amount: Uint256,
amount: U256,
) {
let amount_uint256 = Uint256::from_str(amount.to_string().as_str()).unwrap();
let start_coin = check_cosmos_balance("gravity", dest, &contact).await;
info!(
"Sending to Cosmos from {} to {} with amount {}",
Expand All @@ -239,10 +239,8 @@ async fn test_erc20_deposit(
gravity_address,
amount.clone(),
dest,
*MINER_PRIVATE_KEY,
Some(TOTAL_TIMEOUT),
&web30,
vec![],
(*MINER_CLIENT).clone(),
)
.await
.expect("Failed to send tokens to Cosmos");
Expand All @@ -255,7 +253,7 @@ async fn test_erc20_deposit(
check_cosmos_balance("gravity", dest, &contact).await,
) {
(Some(start_coin), Some(end_coin)) => {
if start_coin.amount + amount.clone() == end_coin.amount
if start_coin.amount + amount_uint256.clone() == end_coin.amount
&& start_coin.denom == end_coin.denom
{
info!(
Expand All @@ -266,7 +264,7 @@ async fn test_erc20_deposit(
}
}
(None, Some(end_coin)) => {
if amount == end_coin.amount {
if amount_uint256 == end_coin.amount {
info!(
"Successfully bridged ERC20 {}{} to Cosmos! Balance is now {}{}",
amount, end_coin.denom, end_coin.amount, end_coin.denom
Expand All @@ -288,7 +286,6 @@ async fn test_erc20_deposit(
async fn test_batch(
contact: &Contact,
grpc_client: &mut GravityQueryClient<Channel>,
web30: &Web3,
dest_eth_address: EthAddress,
gravity_address: EthAddress,
requester_cosmos_private_key: CosmosPrivateKey,
Expand Down Expand Up @@ -349,7 +346,7 @@ async fn test_batch(
.expect("Failed to get batch to sign");

let mut current_eth_batch_nonce =
get_tx_batch_nonce(gravity_address, erc20_contract, *MINER_ADDRESS, &web30)
get_tx_batch_nonce(gravity_address, erc20_contract, (*MINER_CLIENT).clone())
.await
.expect("Failed to get current eth valset");
let starting_batch_nonce = current_eth_batch_nonce;
Expand All @@ -361,7 +358,7 @@ async fn test_batch(
starting_batch_nonce
);
current_eth_batch_nonce =
get_tx_batch_nonce(gravity_address, erc20_contract, *MINER_ADDRESS, &web30)
get_tx_batch_nonce(gravity_address, erc20_contract, (*MINER_CLIENT).clone())
.await
.expect("Failed to get current eth tx batch nonce");
delay_for(Duration::from_secs(4)).await;
Expand All @@ -370,30 +367,27 @@ async fn test_batch(
}
}

let txid = web30
.send_transaction(
dest_eth_address,
Vec::new(),
1_000_000_000_000_000_000u128.into(),
*MINER_ADDRESS,
*MINER_PRIVATE_KEY,
vec![],
)
.await
.expect("Failed to send Eth to validator {}");
web30
.wait_for_transaction(txid, TOTAL_TIMEOUT, None)
.await
.unwrap();
let eth_client = (*MINER_CLIENT).clone();
let tx = TransactionRequest {
from: Some(eth_client.address()),
to: Some(NameOrAddress::Address(dest_eth_address)),
gas: None,
gas_price: None,
value: Some(1_000_000_000_000_000_000u128.into()),
data: Some(Vec::new().into()),
nonce: None,
};

let pending_tx = eth_client.send_transaction(tx, None).await.unwrap();
pending_tx.await.unwrap();

let amount_u256 = U256::from_str(amount.to_string().as_str()).unwrap();

// we have to send this address one eth so that it can perform contract calls
send_one_eth(dest_eth_address, web30).await;
send_one_eth(dest_eth_address, eth_client.clone()).await;
assert_eq!(
web30
.get_erc20_balance(erc20_contract, dest_eth_address)
.await
.unwrap(),
amount
get_erc20_balance(erc20_contract, dest_eth_address, eth_client.clone()).await.unwrap(),
amount_u256
);
info!(
"Successfully updated txbatch nonce to {} and sent {}{} tokens to Ethereum!",
Expand All @@ -405,10 +399,10 @@ async fn test_batch(
// already been submitted to test the nonce functionality.
#[allow(clippy::too_many_arguments)]
async fn submit_duplicate_erc20_send(
nonce: Uint256,
nonce: U256,
contact: &Contact,
erc20_address: EthAddress,
amount: Uint256,
amount: U256,
receiver: CosmosAddress,
keys: &[ValidatorKeys],
) {
Expand Down
Loading

0 comments on commit c72e123

Please sign in to comment.