Closed philippecamacho closed 2 years ago
Note: consider parsing the ethereum transaction receipt.
Data needed for the wallet for updating the sparse data structures for creating new transactions
When a block is committed we need the list of wraps that were inserted in the merkle tree.
@sveitser Should we not simply extract the information from CALL_DATA?
Check if ethers-rs can help for this.
@joe
@philippecamacho @tri-joe @jbearer
Looks doable to get the calldata and deserialize it back into the function input argument of type CapeBlock
. The test below passes.
We can do
There is also https://docs.rs/ethers/0.6.2/ethers/contract/builders/struct.Event.html#method.query_with_meta to get the events with tx hash (and more). I haven't tested this yet though.
See the code is between the // XXX
blocks below.
#[tokio::test]
async fn test_submit_block_to_cape_contract() -> Result<()> {
let contract = deploy_cape_test().await;
// Create three transactions
let rng = &mut ark_std::test_rng();
let num_transfer_txn = 1;
let num_mint_txn = 1;
let num_freeze_txn = 1;
let params = TxnsParams::generate_txns(
rng,
num_transfer_txn,
num_mint_txn,
num_freeze_txn,
CapeLedger::merkle_height(),
);
let miner = UserPubKey::default();
let nf = params.txns[0].nullifiers()[0];
let root = params.txns[0].merkle_root();
// temporarily no burn txn yet.
let cape_block = CapeBlock::generate(params.txns, vec![], miner.address())?;
// Check that some nullifier is not yet inserted
assert!(
!contract
.nullifiers(nf.generic_into::<NullifierSol>().0)
.call()
.await?
);
// TODO should not require to manually submit the root here
contract
.add_root(root.generic_into::<MerkleRootSol>().0)
.send()
.await?
.await?;
// Submit to the contract
let receipt = contract
.submit_cape_block(cape_block.clone().into())
.send()
.await?
.await?;
// XXX
// via block number
let block_num = receipt.clone().unwrap().block_number.unwrap();
use ethers::prelude::{Http, Provider};
use std::convert::TryFrom;
let provider = Provider::<Http>::try_from("http://localhost:8545").unwrap();
let block = provider.get_block_with_txs(block_num).await;
let tx = block.unwrap().unwrap().transactions[0].clone(); // TODO find the right transactions
let decoded: sol::CapeBlock = contract.decode("submitCapeBlock", tx.input).unwrap();
println!("decoded {:?}", decoded);
assert_eq!(decoded, cape_block.clone().into());
// via tx hash
let tx_hash = receipt.unwrap().transaction_hash;
let tx = provider.get_transaction(tx_hash).await.unwrap().unwrap();
let decoded: sol::CapeBlock = contract.decode("submitCapeBlock", tx.input).unwrap();
println!("decoded {:?}", decoded);
assert_eq!(decoded, cape_block.into());
// XXX
// Check that now the nullifier has been inserted
assert!(
contract
.nullifiers(nf.generic_into::<NullifierSol>().0)
.call()
.await?
);
Ok(())
}
@philippecamacho @tri-joe @jbearer
Looks doable to get the calldata and deserialize it back into the function input argument of type
CapeBlock
. The test below passes.We can do
- block number -> block -> transactions -> transaction -> calldata -> CapeBlock
- transaction hash -> transaction -> calldata -> decode -> CapeBlock
There is also https://docs.rs/ethers/0.6.2/ethers/contract/builders/struct.Event.html#method.query_with_meta to get the events with tx hash (and more). I haven't tested this yet though.
See the code is between the
// XXX
blocks below.#[tokio::test] async fn test_submit_block_to_cape_contract() -> Result<()> { let contract = deploy_cape_test().await; // Create three transactions let rng = &mut ark_std::test_rng(); let num_transfer_txn = 1; let num_mint_txn = 1; let num_freeze_txn = 1; let params = TxnsParams::generate_txns( rng, num_transfer_txn, num_mint_txn, num_freeze_txn, CapeLedger::merkle_height(), ); let miner = UserPubKey::default(); let nf = params.txns[0].nullifiers()[0]; let root = params.txns[0].merkle_root(); // temporarily no burn txn yet. let cape_block = CapeBlock::generate(params.txns, vec![], miner.address())?; // Check that some nullifier is not yet inserted assert!( !contract .nullifiers(nf.generic_into::<NullifierSol>().0) .call() .await? ); // TODO should not require to manually submit the root here contract .add_root(root.generic_into::<MerkleRootSol>().0) .send() .await? .await?; // Submit to the contract let receipt = contract .submit_cape_block(cape_block.clone().into()) .send() .await? .await?; // XXX // via block number let block_num = receipt.clone().unwrap().block_number.unwrap(); use ethers::prelude::{Http, Provider}; use std::convert::TryFrom; let provider = Provider::<Http>::try_from("http://localhost:8545").unwrap(); let block = provider.get_block_with_txs(block_num).await; let tx = block.unwrap().unwrap().transactions[0].clone(); // TODO find the right transactions let decoded: sol::CapeBlock = contract.decode("submitCapeBlock", tx.input).unwrap(); println!("decoded {:?}", decoded); assert_eq!(decoded, cape_block.clone().into()); // via tx hash let tx_hash = receipt.unwrap().transaction_hash; let tx = provider.get_transaction(tx_hash).await.unwrap().unwrap(); let decoded: sol::CapeBlock = contract.decode("submitCapeBlock", tx.input).unwrap(); println!("decoded {:?}", decoded); assert_eq!(decoded, cape_block.into()); // XXX // Check that now the nullifier has been inserted assert!( contract .nullifiers(nf.generic_into::<NullifierSol>().0) .call() .await? ); Ok(()) }
Awesome!
There is also a type safe(er) way to do it but I'm running into an issue with ambiguous imports inside the abigen
macro when trying it in the cape repo. ...Call
is provided by the abigen.
Works in a sample repo
let decoded = MyFunctionCall::decode(tx.input).unwrap();
let arg = decoded.my_arg;
In cape it would be
let decoded = SubmitCapeBlockCall::decode(tx.input).unwrap();
let block = decoded.new_block;
The error is
note: `SubmitCapeBlockCall` could refer to the struct imported here
--> contracts/rust/src/types.rs:26:1
|
26 | / abigen!(
27 | | AssetRegistry,
28 | | "../abi/contracts/AssetRegistry.sol/AssetRegistry/abi.json",
29 | | event_derives(serde::Deserialize, serde::Serialize);
... |
94 | |
95 | | );
| |__^
= help: consider adding an explicit import of `SubmitCapeBlockCall` to disambiguate
note: `SubmitCapeBlockCall` could also refer to the struct imported here
--> contracts/rust/src/types.rs:26:1
|
26 | / abigen!(
27 | | AssetRegistry,
28 | | "../abi/contracts/AssetRegistry.sol/AssetRegistry/abi.json",
29 | | event_derives(serde::Deserialize, serde::Serialize);
... |
94 | |
95 | | );
| |__^
= help: consider adding an explicit import of `SubmitCapeBlockCall` to disambiguate
= note: this error originates in the macro `abigen` (in Nightly builds, run with -Z macro-backtrace for more info)
Consider opening an issue on ethers-rs. To reproduce the error I think using a simple contract defining a struct and another contract inheriting from the first contract and putting them both in the abigen may trigger the error. abigen_expanded.rs.txt
The information needed will be specified in #362.