Skip to content

Commit 963af4f

Browse files
authored
add test cases for owner functionality (#51)
* refactor test to abstract deployment logic * add test cases for owner functionality * test upgraded implementation still works
1 parent f613a38 commit 963af4f

File tree

1 file changed

+152
-6
lines changed

1 file changed

+152
-6
lines changed

Diff for: cli/tests/e2e_test.rs

+152-6
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,21 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
use alloy::network::Ethereum;
16+
use alloy::providers::Provider;
17+
use alloy::transports::http::Http;
1518
use alloy::{
16-
network::EthereumWallet, node_bindings::Anvil, primitives::U256, providers::ProviderBuilder,
19+
network::EthereumWallet,
20+
node_bindings::{Anvil, AnvilInstance},
21+
primitives::U256,
22+
providers::ProviderBuilder,
1723
signers::local::PrivateKeySigner,
1824
};
1925
use alloy_sol_types::{sol, SolCall};
2026
use blobstream0_core::{post_batch, prove_block_range};
21-
use blobstream0_primitives::IBlobstream::{self, BinaryMerkleProof, DataRootTuple};
27+
use blobstream0_primitives::IBlobstream::{
28+
self, BinaryMerkleProof, DataRootTuple, IBlobstreamInstance,
29+
};
2230
use reqwest::header;
2331
use serde::{Deserialize, Serialize};
2432
use serde_with::{base64::Base64, serde_as, DisplayFromStr};
@@ -57,13 +65,18 @@ struct DataRootInclusionResponse {
5765
aunts: Vec<Vec<u8>>,
5866
}
5967

60-
#[tokio::test(flavor = "multi_thread")]
61-
async fn e2e_basic_range() -> anyhow::Result<()> {
68+
async fn setup_test_environment() -> anyhow::Result<(
69+
AnvilInstance,
70+
IBlobstreamInstance<
71+
Http<reqwest::Client>,
72+
impl Provider<Http<reqwest::Client>, Ethereum>,
73+
Ethereum,
74+
>,
75+
)> {
6276
// Set dev mode for test.
6377
std::env::set_var("RISC0_DEV_MODE", "true");
6478

6579
// Spin up a local Anvil node.
66-
// Ensure `anvil` is available in $PATH.
6780
let anvil = Anvil::new().try_spawn()?;
6881

6982
// Set up signer from the first default Anvil account (Alice).
@@ -108,8 +121,16 @@ async fn e2e_basic_range() -> anyhow::Result<()> {
108121
)
109122
.await?;
110123
// Pretend as if the proxy is the contract itself, requests forwarded to implementation.
111-
let contract = IBlobstream::new(contract.address().clone(), provider.clone());
124+
let contract = IBlobstream::new(contract.address().clone(), provider);
125+
126+
Ok((anvil, contract))
127+
}
128+
129+
#[tokio::test(flavor = "multi_thread")]
130+
async fn e2e_basic_range() -> anyhow::Result<()> {
131+
let (_anvil, contract) = setup_test_environment().await?;
112132

133+
let tm_client = Arc::new(HttpClient::new(CELESTIA_RPC_URL)?);
113134
let receipt =
114135
prove_block_range(tm_client.clone(), BATCH_START as u64..BATCH_END as u64).await?;
115136

@@ -167,3 +188,128 @@ async fn e2e_basic_range() -> anyhow::Result<()> {
167188

168189
Ok(())
169190
}
191+
192+
#[tokio::test(flavor = "multi_thread")]
193+
async fn test_admin_functions() -> anyhow::Result<()> {
194+
let (_anvil, contract) = setup_test_environment().await?;
195+
196+
// Test adminSetImageId
197+
let new_image_id = [1u8; 32];
198+
contract
199+
.adminSetImageId(new_image_id.into())
200+
.send()
201+
.await?
202+
.watch()
203+
.await?;
204+
let current_image_id = contract.imageId().call().await?;
205+
assert_eq!(current_image_id._0, new_image_id);
206+
207+
// Test adminSetVerifier
208+
let new_verifier = MockVerifier::deploy(contract.provider(), [1, 1, 1, 1].into()).await?;
209+
contract
210+
.adminSetVerifier(new_verifier.address().clone())
211+
.send()
212+
.await?
213+
.watch()
214+
.await?;
215+
let current_verifier = contract.verifier().call().await?;
216+
assert_eq!(current_verifier._0, *new_verifier.address());
217+
218+
// Test adminSetTrustedState
219+
let new_trusted_hash = [2u8; 32];
220+
let new_trusted_height = 100u64;
221+
contract
222+
.adminSetTrustedState(new_trusted_hash.into(), new_trusted_height.into())
223+
.send()
224+
.await?
225+
.watch()
226+
.await?;
227+
let current_trusted_hash = contract.latestBlockHash().call().await?;
228+
let current_trusted_height = contract.latestHeight().call().await?;
229+
assert_eq!(current_trusted_hash._0, new_trusted_hash);
230+
assert_eq!(current_trusted_height._0, new_trusted_height);
231+
232+
Ok(())
233+
}
234+
235+
#[tokio::test(flavor = "multi_thread")]
236+
async fn test_contract_upgrade() -> anyhow::Result<()> {
237+
let (_anvil, contract) = setup_test_environment().await?;
238+
239+
// Deploy a new implementation
240+
let new_implementation = IBlobstream::deploy(contract.provider()).await?;
241+
242+
// Upgrade the contract
243+
contract
244+
.upgradeToAndCall(new_implementation.address().clone(), vec![].into())
245+
.send()
246+
.await?
247+
.watch()
248+
.await?;
249+
250+
// Verify the upgrade
251+
let implementation_slot: U256 = U256::from_str_radix(
252+
"360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc",
253+
16,
254+
)
255+
.unwrap();
256+
let current_implementation = contract
257+
.provider()
258+
.get_storage_at(contract.address().clone(), implementation_slot)
259+
.await?;
260+
assert_eq!(
261+
&current_implementation.to_be_bytes::<32>()[12..32],
262+
new_implementation.address().as_slice()
263+
);
264+
265+
// Test that the new implementation works as normal
266+
let tm_client = Arc::new(HttpClient::new(CELESTIA_RPC_URL)?);
267+
let receipt =
268+
prove_block_range(tm_client.clone(), BATCH_START as u64..BATCH_END as u64).await?;
269+
270+
post_batch(&contract, &receipt).await?;
271+
272+
let height = contract.latestHeight().call().await?;
273+
assert_eq!(height._0, BATCH_END as u64 - 1);
274+
275+
Ok(())
276+
}
277+
278+
#[tokio::test(flavor = "multi_thread")]
279+
async fn test_ownership_transfer() -> anyhow::Result<()> {
280+
let (anvil, contract) = setup_test_environment().await?;
281+
282+
// Get the initial owner
283+
let initial_owner = contract.owner().call().await?;
284+
assert_eq!(initial_owner._0, anvil.addresses()[0]);
285+
286+
// Transfer ownership
287+
let new_owner = anvil.addresses()[1];
288+
contract
289+
.transferOwnership(new_owner)
290+
.send()
291+
.await?
292+
.watch()
293+
.await?;
294+
295+
// Accept ownership (need to switch to the new owner's wallet)
296+
let new_owner_signer: PrivateKeySigner = anvil.keys()[1].clone().into();
297+
let new_owner_wallet = EthereumWallet::from(new_owner_signer);
298+
let new_owner_provider = ProviderBuilder::new()
299+
.with_recommended_fillers()
300+
.wallet(new_owner_wallet)
301+
.on_http(anvil.endpoint().parse()?);
302+
let contract_as_new_owner = IBlobstream::new(contract.address().clone(), new_owner_provider);
303+
contract_as_new_owner
304+
.acceptOwnership()
305+
.send()
306+
.await?
307+
.watch()
308+
.await?;
309+
310+
// Verify the new owner
311+
let final_owner = contract.owner().call().await?;
312+
assert_eq!(final_owner._0, new_owner);
313+
314+
Ok(())
315+
}

0 commit comments

Comments
 (0)